Skip to content

Latest commit

 

History

History
1587 lines (1290 loc) · 90 KB

File metadata and controls

1587 lines (1290 loc) · 90 KB

v0.8.1 correctness and release-trust engineering plan

Status: all owner decisions approved; implementation authorized

Prepared: 2026-08-30

Repository baseline: 1cc9282546224a263ff5885db12b583b8ad10aae

Published release source: v0.8.0 -> 119cbcc7f8d327482df8abfa50a4af0b69fcceee

External audit input: web-app-security-skill-audit.zh-CN.md, SHA-256 4c81aefa04e1345f2f0b09d0618c363069dba52d6d2c750f3b2b00ad34e8ed38

This is the canonical execution plan for v0.8.1. Every completed phase must append an evidence log to section 21 before the next phase starts. The plan may be refined when a fixture disproves an assumption, but a finding may not be silently removed, downgraded or declared fixed.

1. Release objective

v0.8.1 is a correctness and trust-boundary patch. It must make the existing product contract true in six places:

  1. the recorded source roots and exclusions constrain every scanner that claims to use them;
  2. intentional fixtures and reviewed benign matches have a narrow, expiring, visible disposition path without changing their evidence state;
  3. the repository can audit its production code without fixture noise hiding real findings;
  4. Node workspace export resolution and evidence redaction preserve the values their contracts say they preserve;
  5. a GitHub Release cannot be created by the release workflow before the immutable tag and trusted signer are verified against policy sourced from protected main;
  6. CodeQL, Dependabot and historical workflow failures have explicit ownership and disposition instead of an unexplained green or red dashboard.

The release is not a detector-count release. No new vulnerability family is counted toward the stable capability total.

2. Plain-language outcome

After v0.8.1:

  • if a user says "scan only these folders", the tool scans only those folders or says which selected adapter cannot honor that boundary;
  • if a known test fixture intentionally looks vulnerable, the report still records it but can keep it out of the blocking total through a reviewable, exact suppression;
  • changing or expiring that suppression makes the finding active again;
  • a numeric AI usage count such as usage.tokens: 17 remains 17, while an actual access token remains redacted;
  • valid Node package export mappings with repeated right-hand-side * placeholders resolve as Node documents them;
  • unsigned, wrongly signed or wrong-commit release tags stop before write-capable publication;
  • moving v1 no longer creates a predictable generic-CI red window;
  • open platform alerts are fixed or explicitly classified, never merely ignored.

3. Audit method and evidence rules

3.1 Evidence sources inspected

  • the full external audit named above;
  • current main source, workflow, schemas, capability contract and v0.8.0 engineering record;
  • all public GitHub Issues, open and closed, numbers 1 through 7;
  • all ten open CodeQL alerts visible on 2026-08-30;
  • repository branch protection, rulesets, environments and security-analysis settings;
  • recent failed GitHub Actions runs, with the two reported v1 failures reproduced from logs;
  • focused, read-only source-audit and redaction reproductions on the repository itself;
  • official Node subpath-pattern language for repeated right-hand-side wildcard replacement;
  • current TypeScript alias validation in the implementation.

3.2 Result states used in this plan

  • confirmed: the repository source, platform API or a focused reproducer demonstrates the fact;
  • suspected: a credible gap exists, but the causal path or supported input has not been proved;
  • unknown: required platform/runtime evidence is unavailable;
  • not_applicable: the condition is outside v0.8.1's accepted boundary.

A governance absence can be confirmed even when an exploit chain is only conditional. For example, the lack of branch protection is confirmed; compromise of a maintainer account is not.

3.3 Test-budget rule

The plan deliberately avoids repeating the complete matrix after every small edit:

  • each implementation phase runs only the directly affected tests and syntax/schema checks;
  • each silent-regression fix gets one planted-failure demonstration;
  • the final frozen candidate runs npm run check once;
  • if that candidate changes after a failure, the replacement candidate runs the full check once;
  • the hosted four-job Node/macOS/Ubuntu matrix runs once on the pushed candidate;
  • pinned real adapters run only in the existing Ubuntu/Node 22 hosted job unless a focused local adapter reproducer is necessary;
  • live GitHub/npm/installer/Action verification runs only after immutable publication.

4. Finding ledger

ID Priority State Finding v0.8.1 disposition
C-01 P0 conditional confirmed governance gap main has no branch protection, ruleset or release environment; v1 is movable Add minimum branch/tag rules and a release environment after D3. Do not claim account-compromise prevention.
C-02 P0 confirmed tag-triggered release has write/attestation permissions and never calls cryptographic git verify-tag before publication Replace tag-triggered publication with trusted-main dispatch, trusted signer verification and split permissions.
C-03 P0 confirmed sourceRoots and excludedDirectories are recorded and hashed but are not passed to built-in or external scans Implement one canonical scope predicate and adapter-specific fail-closed scope handling.
C-04 P0 confirmed default self-scan reports 14 findings, including intentional fixtures and one benign rule-registry match, with no structured suppression Ship narrow suppression/disposition and a production-only self-audit gate.
C-05 P0 confirmed Node exports RHS replaces only the first *, contrary to Node's all-instance replacement rule Replace every RHS wildcard literally and add adversarial path tests.
C-06 P1 confirmed ten CodeQL alerts are open and Dependabot alerts/security updates are disabled Fix production alerts, disposition test alerts, accept an owner policy, then inventory dependency alerts.
C-07 P1 confirmed numeric usage.tokens becomes [REDACTED] Make redaction type- and key-aware without weakening credential cleaning.
C-08 P1 confirmed failure; cause bounded repeated v1 promotions trigger generic CI while the moving tag and recorded stable state temporarily disagree Separate local consistency from live promotion verification and stop generic CI from running on moving tags. Do not label this a race without further proof.
A-01 P0 support confirmed scope boundary arrays are not structurally validated beyond their digest Validate path grammar, duplicates, limits, roots, exclusions and symlink behavior before execution.
A-02 P1 confirmed TypeScript path targets are limited to at most one wildcard, so CodeQL alert 9 is not the same bug as C-05 Refactor to a one-wildcard literal helper or dismiss only after the invariant is machine-proved. Never apply Node replaceAll semantics mechanically.
A-03 P1 review suspected capability gap Node conditional export traversal recognizes only import, default, require and types Plant node/custom-condition fixtures. If one exact source target can be retained, fix; otherwise fail closed and document the condition boundary.
A-04 P1 confirmed secret scanning and push protection are already enabled, but Issue 7's title/body still describe pre-enable work Correct the issue record; only Dependabot enablement and alert ownership remain undecided.
A-05 P2 confirmed Issue 3 says the compatibility table claims WSL2 support, while the current table explicitly says unsupported Keep the issue open as future verification work; do not invent a WSL2 pass for v0.8.1.

5. Reproduction inventory

5.1 Scope disconnect

Current orchestration sends the whole project root to both scanner families:

  • scripts/project-audit.mjs:223-230 invokes auditSource(projectRoot, ...) and runExternalAdapters(projectRoot, ...) without the recorded roots/exclusions;
  • scripts/lib/source-audit.mjs:13-17 owns a hard-coded IGNORED set;
  • scripts/lib/source-audit.mjs:383-385 accepts a root and limits but no scope policy;
  • scripts/lib/external-adapters.mjs independently hard-codes roots and excludes for each adapter;
  • scripts/lib/project-identity.mjs:180-213 validates the digest but does not validate or apply the two boundary arrays.

The default arrays currently resemble the hard-coded values. That accidental agreement does not make the persisted contract operational and does not cover a modified, narrower scope.

5.2 Repository self-scan

The built-in source audit at the frozen baseline emits 14 findings:

  • four confirmed: two tracked .env.production fixtures and two fixture manifests without a lockfile;
  • nine suspected: intentional quickstart/insecure-demo/test patterns plus one cors-wildcard-with-credentials match in scripts/lib/source-rule-registry.mjs:354;
  • one unknown: incomplete route evidence caused by the mixed full-repository surface;
  • four HIGH, eight MEDIUM and two LOW severities.

This result is not evidence that the released tool has four confirmed vulnerabilities. It is evidence that the repository has no first-class way to separate production code, deliberate vulnerable examples and reviewed benign scanner matches.

5.3 Module replacement

scripts/lib/js-ts-module-graph.mjs:541-545 uses target.replace('*', wildcard) for Node package exports. Official Node documentation states that every * on the right-hand side is replaced.

The TypeScript path branch at line 499 is different: config parsing at lines 186-197 rejects both patterns and targets with more than one wildcard. It needs an explicit one-wildcard implementation, not the Node multi-wildcard fix copied blindly.

5.4 Evidence redaction

The focused result is:

{"usage":{"tokens":"[REDACTED]","inputTokens":8},"accessToken":"[REDACTED]"}

scripts/lib/evidence-writer.mjs:22-45 singularizes tokens to token, and lines 84-95 redact non-string scalars under a secret-looking key. This protects credentials but corrupts a common numeric usage counter.

5.5 Release and promotion

  • .github/workflows/release.yml:2-9 is triggered by a SemVer tag and grants write, ID-token and attestation permissions to the workflow;
  • lines 21-27 check version and files but do not cryptographically verify the tag;
  • gh release create --verify-tag at lines 48-57 verifies that the tag exists, not its SSH/GPG signer;
  • signer policy read from a tag checkout would be attacker-controlled if the attacker can also select the tag commit, so the trusted policy must come from protected main or another immutable trust root;
  • generic CI currently uses on: [push, pull_request], so a forced v1 tag update starts the full matrix;
  • failed runs 33265040656 and 32980990347 both stopped on v1 differs from the recorded stable Action source commit; older promotions show the same class of failure.

The repeated failures prove an exposed intermediate-state invariant. They do not by themselves prove concurrent writers or a timing race.

6. v0.8.1 scope and non-goals

6.1 Included

  • canonical scope compilation and validation;
  • built-in, route, diff and external-adapter scope enforcement;
  • visible, exact suppression/disposition;
  • report/schema/renderer/gate/baseline integration for suppression;
  • production-only repository self-audit;
  • Node export replacement and bounded conditional-export review;
  • type-aware redaction correction;
  • release signer gate and least-privilege job split;
  • explicit v1 promotion lifecycle and live-state verification;
  • CodeQL disposition, Dependabot decision and Issue 7 owner policy;
  • checksum-pinned ShellCheck if D5 is approved;
  • synchronized version, capability, limitation and release documentation.

6.2 Excluded

  • new secret, XSS, SQLi, authz or security.txt detector families;
  • MCP or a remote service;
  • Strix or another scanner-as-a-service dependency;
  • authenticated DAST or automatic exploitation;
  • production precision/recall claims;
  • a new ORM/framework/language family;
  • arbitrary code-coverage percentages;
  • claiming WSL2 support without a clean maintained runner;
  • requiring a second reviewer when the repository still has one maintainer;
  • rewriting all release infrastructure only to improve ceremony metrics.

7. Canonical scope contract

7.1 One policy object

Add one module that compiles the persisted boundary into an immutable policy object. Its public operations must be sufficient for all consumers:

compileAuditScope(projectRoot, auditBoundary)
  -> roots
  -> excludedDirectoryNames
  -> includes(relativePath)
  -> classify(relativePath)
  -> governingInputs(manifests, lockfiles)
  -> scopeDigest

No scanner may rebuild the policy from a separate hard-coded list.

7.2 Validation

Before reading target files:

  • sourceRoots is a non-empty bounded array of unique POSIX-relative paths;
  • . is allowed; absolute paths, backslashes, NUL/control bytes, empty segments and .. are rejected;
  • each root resolves lexically and physically inside projectRoot;
  • a missing, unreadable or symlink root becomes an explicit scope error or unavailable coverage, never a clean scan;
  • overlapping roots are de-duplicated without double-counting coverage;
  • excludedDirectories is a bounded unique array of directory basenames, not path globs;
  • .git and .webapp-security remain mandatory engine-safety exclusions even if omitted by a hand-edited scope; the report distinguishes mandatory and user-recorded exclusions;
  • every normalized boundary used by execution is the same value used for scopeDigest.

7.3 File-read semantics

The recommended D1 decision is that scope is a file-read boundary, not merely an output filter. Under that decision:

  • excluded files are not opened by the built-in analyzer;
  • route/access analysis receives only parsed files admitted by the same policy;
  • tracked-sensitive-env Git queries use pathspecs for admitted roots and post-validate every path;
  • diff snapshots preserve repository-relative layout and then apply the same policy;
  • coverage records excluded, missing and unavailable roots with reason codes;
  • paths outside scope cannot appear in findings, patches, route artifacts or sampled coverage reasons;
  • discovery may identify the repository layout, but it may not upgrade out-of-scope source to scanned evidence.

7.4 Manifests and lockfiles

Root workspace metadata may govern a nested source root. Therefore a manifest/lockfile input is eligible only when it is:

  • inside an admitted source root; or
  • an ancestor-level recorded project/workspace input that governs at least one admitted root;
  • not inside an excluded directory;
  • contained by lexical and realpath checks.

The report must identify these as governing_input, rather than pretending they were ordinary source files inside the root.

7.5 Existing baseline compatibility

  • a v0.8.0 scope with the exact generated default boundary remains comparable because its effective built-in exclusion behavior is unchanged;
  • a pre-v0.8.1 baseline with a non-default boundary is not_comparable / scope_enforcement_changed, because the previous run did not prove that boundary;
  • a changed root or exclusion still changes scopeDigest and requires a new baseline;
  • scope migration never rewrites an old report or calls its excluded paths scanned.

8. External-adapter scope matrix

Adapter v0.8.1 scope behavior Failure boundary
Checkov Build its exact Dockerfile/workflow input list through the canonical predicate; verify every returned path is in that list No eligible input -> not_applicable; unexpected returned path -> unknown, not filtered success
OSV-Scanner Pass only admitted/governing lockfiles after lexical and realpath containment Excluded or escaping lockfile is not scanned; invalid recorded inputs make coverage unavailable
Opengrep Scan a private, deterministic, path-preserving scoped snapshot or an equivalently exact supported target list If exact file-read scoping cannot be proved, do not run broader and post-filter; return scope_not_supported unknown
Gitleaks working tree Use an exact scoped snapshot with no Git history and map paths back to the project Excluded content must not be read merely to discard its finding
Gitleaks history Preserve current full-repository behavior only for the default full scope A restricted custom scope is unknown / history_scope_not_supported until a pinned version can prove an exact history path boundary

Every adapter result records scopeMode (full, scoped_snapshot, governing_inputs or unsupported) in report scope metadata. A selected adapter that cannot honor a restricted scope must contribute unknown evidence and exit 3 under the current precedence. Missing capability may not become zero findings.

9. Suppression and disposition contract

9.1 Separation from evidence state

Suppression is a policy disposition, not a fifth evidence state. A suppressed suspected finding remains suspected; a suppressed confirmed finding remains confirmed. Reports and baselines retain the finding and its fingerprint.

9.2 Versioned file

Use a repository-root JSON file, proposed name webapp-security.suppressions.json:

{
  "schemaVersion": 1,
  "subjectId": "project-...",
  "entries": [
    {
      "id": "suppression-...",
      "adapterId": "builtin",
      "ruleId": "cors-wildcard-with-credentials",
      "path": "scripts/lib/source-rule-registry.mjs",
      "fingerprint": "<64 lowercase hex>",
      "reason": "Rule metadata contains the safe near-neighbour text used by the detector corpus.",
      "owner": "@parousia8888",
      "createdAt": "<RFC3339>",
      "expiresAt": "<RFC3339>"
    }
  ]
}

9.3 Validation and security properties

  • reject symlinks, paths outside the target, files over a small documented size and duplicate IDs;
  • reject unknown fields, malformed timestamps, expiry before creation and control characters;
  • require exact adapter, rule, relative path and fingerprint match;
  • any path, rule revision or evidence fingerprint drift invalidates the entry;
  • an expired entry is retained in diagnostics but does not suppress;
  • a malformed file makes suppression coverage unavailable and cannot weaken the gate;
  • unknown and evidence_integrity findings are never suppressible;
  • reasons are sanitized before rendering and never interpreted as code;
  • suppression cannot change coverage status, baseline state or fixed classification;
  • a broad rule-only or directory-wide allowlist is not accepted in v0.8.1.

9.4 Owner/expiry policy

Recommended D2 decision:

  • reason is always required;
  • owner and expiresAt may be omitted for a local evidence-only report;
  • both become mandatory when a suppression affects a CI/release gate;
  • external-adapter suppressions always require owner and expiry, matching docs/alert-policy.md.

9.5 Report and renderer behavior

Add an optional additive v3 finding disposition object and summary counts:

  • disposition.status: active or suppressed;
  • suppression ID, reason, owner and expiry only when valid and sanitized;
  • summary.activeTotal, summary.suppressedTotal and summary.byDisposition;
  • existing summary.total and state/severity/domain counts continue to describe all retained findings;
  • Markdown/HTML place a visible SUPPRESSED label and expiry beside the finding;
  • SARIF uses the standard external suppression shape and keeps the result;
  • JUnit represents a valid suppression as skipped, not passed;
  • JSON is the source of truth for every renderer.

The gate evaluates active findings only. Incomplete/unknown evidence remains non-suppressible and keeps exit 3. Removing or expiring a suppression can make an unchanged finding block again.

9.6 Baseline behavior

  • adding suppression does not make a baseline finding fixed;
  • removing suppression does not make it new if its evidence fingerprint is unchanged;
  • an absent finding becomes fixed only after completed comparable coverage;
  • moved-condition matching happens before disposition and keeps current v3 identity semantics;
  • suppression-file changes are recorded in report scope/policy digest but do not rewrite the source evidence fingerprint.

10. Repository self-audit contract

Add one documented, deterministic repository self-audit with these surfaces:

  • production source and runtime packaging files are in scope;
  • test, intentional vulnerable examples, generated adoption material and release archives are explicitly excluded and counted;
  • root manifests/workflows remain governing inputs where applicable;
  • the rule-registry benign match receives one exact suppression only if a focused review confirms the path/fingerprint on the final scope;
  • no unknown/evidence-integrity result may be suppressed;
  • CI fails on an active HIGH or above finding and on incomplete evidence;
  • all suppressed findings remain in an uploaded report artifact;
  • the gate runs without network and without external adapters.

The first clean self-audit is a regression fixture for scope and suppression. It is not a claim that the project has no vulnerabilities.

11. Module-resolution corrections

11.1 Node export patterns

Use literal callback replacement or an equivalent slice-based helper so wildcard text containing $&, $1, $$ or path separators is never interpreted as JavaScript replacement syntax.

Required cases:

  • zero wildcard RHS;
  • one wildcard RHS;
  • two or more RHS wildcards all receiving the exact captured subpath;
  • conditional export object and array fallback;
  • captured value containing /, $ and dotted filenames;
  • null/private export targets;
  • result escaping the workspace root;
  • one exact resolution, multiple resolution ambiguity and missing target.

11.2 TypeScript paths

Keep the existing one-wildcard grammar. Replace through an exact helper whose precondition is proved by config validation. Add a test that a second wildcard remains module_config_alias_invalid.

CodeQL alert 9 may be closed only when the code-level invariant is visible to the query or the live alert is dismissed with the fixture/test proof. It is not evidence of C-05 by itself.

11.3 Conditional exports

Plant exact node, nested node -> import, custom condition and ambiguous-condition fixtures.

  • if all supported branches resolve to one source, retain that source;
  • if branches resolve to different sources and runtime conditions are unknown, return an explicit ambiguity reason;
  • do not choose a convenient branch by object key name;
  • if this cannot be implemented narrowly, add a known limitation and keep partial access coverage.

This review is bounded to workspace source resolution. It does not attempt the complete Node module resolver.

12. Redaction correction

The allow rule is narrow:

  • preserve a finite numeric scalar under exact usage-counter keys such as tokens, tokenCount, inputTokens, outputTokens, promptTokens, completionTokens and totalTokens;
  • do not preserve numeric accessToken, refreshToken, idToken, credential, password, secret or API-key values;
  • do not treat arrays of numeric token IDs as usage counts;
  • continue to redact strings under every secret key, even when the string contains digits;
  • preserve normal booleans/nulls only where the existing evidence schema permits them;
  • preserve nested authorization evidence exceptions already covered by the current model;
  • render the same sanitized value in JSON, Markdown, HTML, SARIF and JUnit.

Required adversarial fixtures include numeric access tokens, stringified counts, arrays, nested credentials, mixed-case/snake-case key variants and a normal usage.tokens counter.

13. Release trust architecture

13.1 Trigger and trust root

Replace automatic tag-push publication with workflow_dispatch from main and explicit inputs for version/tag. The workflow must reject execution unless github.ref is refs/heads/main.

Use two checkouts or equivalent immutable separation:

  1. trusted orchestration and .github/release-signers from protected main;
  2. candidate source from the input immutable tag.

The candidate is untrusted until the main-sourced verifier proves:

  • the tag is an annotated tag object;
  • git verify-tag succeeds against the trusted allowlist;
  • the peeled commit equals the declared source commit;
  • VERSION, package version, release evidence and manifest version agree;
  • the source commit is reachable from the approved candidate commit on origin/main;
  • hosted CI and CodeQL succeeded on that exact source commit;
  • the tag and release do not already exist in a conflicting state.

npm ci --ignore-scripts, artifact construction and all write-capable operations occur only after this verification.

13.2 Permission split

Use separate jobs:

  • verify-and-build: contents: read, no ID token, no attestations, no environment;
  • publish: needs verified artifacts, has contents: write, id-token: write and attestations: write, and uses the protected release environment;
  • post-publish-verify: read-only except for uploading workflow evidence, verifies public assets and provenance.

Workflow-level write permissions are forbidden. Release concurrency is one non-cancelling group so two versions cannot publish simultaneously.

13.3 Trusted policy bootstrap

A tag commit must not be able to replace its own trusted signer list or verifier. Tests must create a candidate commit with an attacker key and modified signer file, sign its tag with that key and prove the main-sourced verifier rejects it.

13.4 v1 promotion lifecycle

Generic CI becomes branch-scoped to main and pull requests to main; it does not run on arbitrary tag updates. Live moving-tag consistency remains a dedicated promotion check.

Model promotion explicitly:

  1. record a pending candidate with prior v1 tag object and expected new source;
  2. verify immutable GitHub/npm/installer/Action channels;
  3. create and locally verify the new signed annotated v1 tag;
  4. update only the expected prior remote tag object under the recorded lease;
  5. run the final immutable plus v1 consumer workflow under promotion concurrency;
  6. finalize stableAction and clear pending state;
  7. run check-public-release-state only after the final state is coherent.

No ordering can make two independent Git refs transactional. The contract is an explicit pending state with dedicated verification, not a claim of atomic multi-ref mutation.

14. GitHub governance and alert policy

14.1 Minimum repository controls

After D3, configure and re-read through the API:

  • protect main from force-push and deletion;
  • require the selected CI and CodeQL checks before merge;
  • keep administrator bypass behavior explicit;
  • protect immutable v0.* tags from update/deletion;
  • keep v1 movable only through the documented promotion authority;
  • create the release environment used by the publish job;
  • do not require a second approving reviewer until a second maintainer exists.

Screenshots are supporting evidence only. API state is the recorded result.

14.2 Current CodeQL disposition

Alert Path class Planned action
10 production module graph Fix C-05 and require the alert to close on the candidate.
9 production module graph Prove the one-wildcard TypeScript invariant, refactor exact replacement, then close or evidence-based dismiss.
11 renderer test Inspect escaping context; fix if output can execute, otherwise dismiss as test-only with ledger evidence.
7, 6, 5 deliberately vulnerable fixture Dismiss as used in tests; link fixture purpose and regression.
4, 3 report contract test strings Inspect generated output path, then dismiss only if values never become unescaped production output.
2 sitemap test Preserve the XSS regression assertion; dismiss as test-only only after the production renderer remains escaped.
1 version consistency test Prove fixed literal comparison and dismiss as test-only/false positive.

Create docs/code-scanning-dispositions.md with alert ID, rule, path, classification, evidence, owner, date and revisit condition. The release gate is:

  • zero new undispositioned production-path HIGH alerts;
  • zero open product-code alert known to represent a confirmed bug;
  • test/fixture alerts may remain dismissed with the public ledger;
  • a successful CodeQL workflow is not equivalent to zero alerts.

14.3 Dependabot and secret scanning

Current platform facts:

  • secret scanning: enabled;
  • secret-scanning push protection: enabled;
  • Dependabot security updates: disabled;
  • Dependabot vulnerability alerts endpoint: unavailable/disabled;
  • no .github/dependabot.yml exists.

Under the approved D4 rollout and ownership policy:

  1. record signal owner, SLA, private escalation and gate authority;
  2. enable vulnerability alerts and Dependabot security updates;
  3. inventory and disposition the resulting alerts and generated security-update PRs;
  4. enable a blocking dependency-review gate after a planted disallowed-dependency fixture proves the evidence path;
  5. keep alert availability separate from merge-gate availability and evidence;
  6. treat unavailable plan/platform features as unavailable, not pass.

14.4 ShellCheck and coverage

Issue 6 contains two separable requests:

  • a checksum-pinned ShellCheck job is a bounded v0.8.1 supply-chain improvement if D5 approves it;
  • Node coverage should be measured as research only. No arbitrary percentage becomes a patch release gate.

Issue 6 remains open unless both its own acceptance criteria are met. Partial work gets an exact issue comment, not a premature close.

15. GitHub Issue disposition

Issue v0.8.1 action Closure rule
1 Run the existing crawler malformed/empty/stale regression in the final suite only Remains closed unless regression fails
2 Run the existing AWS permission-denied regression in the final suite only Remains closed unless regression fails
3 Correct stale premise if needed; keep WSL2 unsupported Keep open until a real clean WSL2 lifecycle exists
4 No implementation in a correctness patch Keep open for a later feature release
5 Run existing sitemap entity/CDATA regression in the final suite only Remains closed unless regression fails
6 Optionally ship pinned ShellCheck; measure coverage without a floor Keep open if coverage/ownership acceptance is incomplete
7 Update current secret-scanning facts; accept owner policy; implement suppression and dependency-alert decision Close only after D4 and live setting/fixture evidence

16. Phase plan

P0 - freeze evidence and owner decisions

Tasks:

  • preserve the external audit hash, repository commit, release source and platform snapshots;
  • record all finding states without copying the audit's severity labels uncritically;
  • obtain D1-D5 decisions;
  • freeze v0.8.1 included/excluded scope;
  • create no version bump and no public release.

Gate:

  • every external finding maps to a phase or explicit defer reason;
  • every open Issue and CodeQL alert maps to a disposition;
  • unresolved owner decisions remain visible and block their dependent phases only.

P1 - plant focused failing contracts

Tasks:

  • add minimal tests for ignored custom source roots/exclusions;
  • add built-in, tracked-env, route and diff scope fixtures;
  • add one fake-adapter scope fixture per adapter family;
  • add suppression expiry/fingerprint/unknown-state failures;
  • add Node multi-RHS-wildcard and replacement-string adversarial fixtures;
  • add numeric usage-token and numeric credential redaction fixtures;
  • add trusted-main versus attacker-tag signer fixture;
  • add a release-state fixture for pending v1 promotion.

Plant-the-failure gate:

  • every test fails against v0.8.0 for the intended reason;
  • test-only syntax errors or wrong fixture assumptions do not count;
  • record test names and pre-fix failure messages in section 21.

P2 - canonical built-in scope enforcement

Tasks:

  • implement and validate the canonical scope object;
  • remove the separate IGNORED source of policy truth;
  • apply it to walking, reading, tracked env files, config/manifest inputs and route/access analysis;
  • apply it to staged/since snapshots;
  • add scope coverage and reason codes;
  • preserve default-boundary baseline compatibility and reject unreliable custom legacy baselines.

Focused gate:

  • only admitted files are opened and reported;
  • excluded vulnerable fixture produces no finding and increments exclusion evidence;
  • unreadable/missing root is unknown/non-zero;
  • no outside path leaks into any renderer;
  • reverting one scope-policy call makes a focused test fail.

P3 - external adapter scope enforcement

Tasks:

  • implement the matrix in section 8;
  • make Checkov and OSV explicit-input scope exact;
  • implement private scoped snapshots for Opengrep and working-tree Gitleaks;
  • make restricted Gitleaks history fail closed if exact history scope is unavailable;
  • record adapter scope mode and network behavior;
  • preserve default full-scope deep-profile behavior.

Focused gate:

  • fake adapters prove excluded marker content was not read;
  • unexpected output paths become unknown;
  • real pinned adapters run once on hosted Ubuntu/Node 22;
  • missing/unsupported scope is not a pass;
  • snapshot cleanup occurs on success, failure and timeout.

P4 - suppression, report and baseline integration

Tasks:

  • implement the versioned suppression parser and exact matcher;
  • extend v3 schemas and runtime validators additively;
  • update summary, JSON, Markdown, HTML, SARIF and JUnit;
  • update exit/gate logic without changing evidence states;
  • preserve fixed/unretested/not-comparable baseline semantics;
  • document and test local versus blocking owner/expiry rules.

Focused gate:

  • valid exact suppression does not block but remains visible;
  • stale, expired, malformed, broad or symlink suppression cannot weaken the gate;
  • unknown/evidence-integrity remains non-suppressible and exit 3;
  • all renderers agree on active/suppressed counts;
  • plant removal of fingerprint or expiry validation is caught.

P5 - self-audit and alert-disposition surface

Tasks:

  • define the production-only repository scope;
  • classify the 14 baseline self-findings through scope or exact suppression, never deletion;
  • add the no-network self-audit CI job and artifact;
  • add the CodeQL disposition ledger;
  • update false-positive and alert policies;
  • confirm closed historical Issue regressions still exist.

Focused gate:

  • intentional examples/tests are excluded with counts;
  • the production rule-registry match is either fixed or exactly suppressed with review evidence;
  • active HIGH and unknown results fail the self-gate;
  • the report contains every suppression;
  • no claim says self-audit proves repository safety.

P6 - module graph and redaction corrections

Tasks:

  • fix Node all-instance RHS wildcard replacement;
  • refactor TypeScript one-wildcard replacement without semantic expansion;
  • resolve or document bounded conditional-export fixtures;
  • implement numeric usage-counter preservation;
  • retain numeric credential and array redaction;
  • update relevant known limitations.

Focused gate:

  • CodeQL production alerts 9/10 have code-level outcomes;
  • all replacement-string adversarial cases pass;
  • access-chain partial/completed semantics do not silently widen;
  • all renderer redaction outputs agree;
  • reverting each correction is caught by its focused test.

P7 - release and v1 workflow correction

Tasks:

  • convert release to trusted-main manual dispatch;
  • split verify/build and publish permissions;
  • bind publish to release environment and concurrency;
  • source verifier and signer policy from trusted main;
  • branch-scope generic CI;
  • add explicit pending/final promotion state;
  • update release scripts/tests/runbook.

Focused gate:

  • unsigned tag, wrong signer, tag-owned signer file and wrong peeled commit all stop before publish;
  • read-only job cannot create a release or attestation;
  • publish job cannot run without verified artifacts/environment;
  • v1 pending state is not a generic CI failure;
  • final live-state mismatch still fails the dedicated verifier;
  • no public tag/release/npm mutation occurs in local tests.

P8 - platform governance and Issue updates

Tasks dependent on decisions:

  • apply and re-read main/tag rules and release environment after D3;
  • accept owner/SLA/escalation fields after D4;
  • enable and inventory Dependabot alerts after D4;
  • add checksum-pinned ShellCheck after D5;
  • post evidence-based comments to Issues 3, 6 and 7;
  • dismiss only classified CodeQL test/fixture alerts through the API.

Gate:

  • live API JSON is retained in a sanitized evidence record;
  • unavailable settings remain unavailable;
  • no issue closes on documentation intent alone;
  • no alert is dismissed without the public disposition ledger.

P9 - documentation and capability synchronization

Tasks:

  • update SKILL.md execution instructions only where behavior changed;
  • update capability JSON/Markdown without increasing stable detector-family count;
  • update README English/Chinese, tutorial, compatibility, false-positive policy, alert policy, known limitations, roadmap and changelog;
  • document scope, suppression, report schema additions and release workflow;
  • update npm/Skill/Action distribution allowlists for new runtime files;
  • keep engineering/adoption evidence out of the runtime package unless required.

Gate:

  • generated capability and public docs agree;
  • every new claim points to a test or schema;
  • WSL2 remains unsupported;
  • no 0 FP, production precision or exploitability claim is added.

P10 - freeze the local v0.8.1 candidate

Tasks:

  • bump VERSION/package/plugin/Action/release surfaces together;
  • generate release evidence and candidate SBOM;
  • run changed-script syntax and schema validation;
  • run one final npm run check on the frozen candidate;
  • run Bash 3.2 smoke and package isolation/distribution checks;
  • record exact pass/fail/skip/not-run inventory.

Gate:

  • zero failed or not-run required tests;
  • optional real adapters may be skipped locally only when recorded and are run hosted;
  • no unexplained dirty file or generated drift;
  • candidate commit is exact and no release tag exists.

P11 - hosted candidate verification

Tasks:

  • push the candidate commit to main without a release tag;
  • wait for CI and CodeQL on the exact commit;
  • run the pinned real-adapter job once;
  • run the repository self-audit and upload its report;
  • query live CodeQL/Dependabot/ruleset/environment state.

Gate:

  • exact candidate CI and CodeQL conclude success;
  • no undispositioned production HIGH alert;
  • no active HIGH or unknown self-audit result;
  • branch/rules/environment facts match the approved D3 state;
  • any correction creates a new candidate and returns to P10.

P12 - immutable release, npm and stable Action promotion

Tasks:

  • create the SSH-signed annotated v0.8.1 tag locally;
  • dispatch the trusted-main release workflow with exact version/tag;
  • verify release assets, checksums, SBOM, attestation and signed tag;
  • publish npm through trusted publishing and verify provenance/file identity;
  • run exact-version npx and verified installer under a fresh isolated home;
  • run the immutable full-SHA Action consumer;
  • acquire the exact v1 lease, enter pending state, sign/move v1, run final consumers and finalize stable state;
  • append final evidence to this plan and docs/releases/v0.8.1.md.

Gate:

  • tag, manifest, GitHub assets, npm gitHead, immutable Action and v1 peel to one source commit;
  • repository-local signer verification and GitHub signature status both pass;
  • npm package and source archive agree on every shipped path;
  • required-attestation install passes;
  • final public-state verifier passes only after pending promotion is cleared;
  • main, npm, GitHub Release, installer default and public docs all name v0.8.1.

17. Test matrix

17.1 Scope matrix

Case Expected result
default . plus default excludes Behavior compatible with v0.8.0 default scan
one nested root Only nested source plus governing inputs
two overlapping roots Files counted once
excluded directory inside root Never opened; exclusion counted
missing root unavailable/unknown, non-zero
symlink root or symlink child refused or explicitly excluded, never followed
tracked env outside root absent from finding; not read
staged/since outside root excluded from diff artifact
route mount outside root cannot supply hidden context; coverage explains absence
custom old baseline not comparable when prior enforcement was unproved

17.2 Suppression matrix

Case Expected result
exact active match retained as suppressed; gate ignores only that finding
wrong path/rule/fingerprint active finding plus unmatched-entry diagnostic
expired entry active finding plus expiry diagnostic
malformed/symlink file suppression unavailable; gate not weakened
unknown/evidence-integrity suppression rejected
suppression added between baseline/current unchanged evidence; disposition changes only
suppression removed unchanged evidence becomes active
finding absent under completed coverage fixed regardless of prior disposition

17.3 Release matrix

Case Expected result
signed by allowed signer verify job may build
unsigned tag stop before dependency install/publication
signed by unlisted key stop before publication
tag commit changes allowlist still rejected by main-sourced allowlist
tag peels to wrong commit rejected
CI status belongs to different commit rejected
concurrent dispatch serialized without cancelling active publication
v1 moved while pending no generic CI red; dedicated state says pending
stale prior v1 lease remote update refused

18. Release stop conditions

Stop v0.8.1 publication if any condition holds:

  • a selected scanner reads or reports a path outside its claimed restricted scope;
  • an adapter silently post-filters broader reads while claiming scoped execution;
  • malformed, expired or broad suppression weakens a gate;
  • suppressed findings disappear from primary evidence;
  • unknown evidence can be suppressed or rendered as pass;
  • Node export correction increases completed access paths through an ambiguous target;
  • redaction preserves a numeric credential or leaks a string token;
  • release verification trusts signer policy from the candidate tag;
  • a write-capable release job can start before verification;
  • generic CI still predictably fails solely because v1 is in documented pending promotion;
  • an open production CodeQL HIGH representing a confirmed bug remains undispositioned;
  • required GitHub control state cannot be read back after D3;
  • final candidate tests, hosted checks, package identity, attestation or consumers disagree;
  • documentation claims WSL2, precision/recall, exploitability or detector expansion not proved here.

19. Definition of done

v0.8.1 is complete only when:

  • all confirmed C-02 through C-08 product/workflow defects assigned to the release are fixed and regression-tested;
  • C-01 repository controls match the owner's D3 decision and residual bypass limits are documented;
  • scope is operational across every selected scanner or explicitly unavailable per adapter;
  • suppression is narrow, visible, expiring under gates and cannot hide incomplete evidence;
  • the repository self-audit is useful and reviewable rather than fixture-noise-free by deletion;
  • CodeQL alerts have live and documented dispositions;
  • Dependabot state matches D4 and is not described as pass when disabled/unavailable;
  • Issues 1-7 have accurate status/comments;
  • the complete candidate/local/hosted/public evidence chain identifies one immutable source;
  • v0.8.1 GitHub Release, npm package, installer default and signed v1 are live and verified;
  • section 21 records every phase, deviation, failed gate and residual limitation.

20. Owner decision gates

D1 - meaning of restricted scope

Decision: approved on 2026-08-30. Scope is a file-read boundary, not an output-only filter.

Consequence: excluded source cannot be opened by a scanner that claims scoped execution. An adapter that cannot prove this boundary must return unknown instead of scanning broadly and filtering its results.

Blocks resolved: P2 and P3 may implement the contract in sections 7 and 8.

D2 - suppression governance

Decision: approved on 2026-08-30. Owner and expiry are optional for local evidence-only use and mandatory when a suppression changes a CI/release gate or external-adapter result.

Consequence: the local path remains usable by an individual, while a blocking suppression cannot be anonymous or permanent.

Blocks resolved: P4 may implement the contract in section 9.

D3 - GitHub branch/tag/environment controls

Decision: minimum protection approved on 2026-08-30. Execution is authorized to:

  • protect main from force-push/deletion;
  • require CI and CodeQL checks;
  • protect immutable SemVer tags;
  • create release environment;
  • retain a documented solo-maintainer bypass without requiring a nonexistent second reviewer.

Consequence: direct destructive ref changes are constrained, while the single maintainer is not blocked by a fabricated second-reviewer requirement. Live API readback remains required before C-01 can close.

D4 - alert ownership and Dependabot

Rollout decision: approved on 2026-08-30. Enable vulnerability alerts, Dependabot security updates and a blocking pull-request dependency-review gate after the planted gate fixture passes.

Approved ownership values:

  • signal owner/update owner/gate authority: @parousia8888;
  • private escalation: the private address/process already named by SECURITY.md;
  • triage targets: one business day for a HIGH secret and three business days for a dependency finding.

Blocks resolved: live enablement, PR blocking and Issue 7 closure may proceed after their planted fixtures and live evidence gates pass.

D5 - ShellCheck in v0.8.1

Decision: approved on 2026-08-30. Include checksum-pinned ShellCheck and leave coverage-floor research open without a percentage gate.

Consequence: ShellCheck runs in CI through a reviewed fixed artifact path and is not downloaded or executed by normal CLI users.

Blocks resolved: the ShellCheck portion of P8 is included.

21. Phase execution log

Append one entry after every phase. Do not pre-mark future work complete.

Required format:

### YYYY-MM-DD - Pn complete / blocked

- Start commit and end commit:
- Finding/Issue/alert IDs addressed:
- Files and behavior changed:
- Focused commands and exact outcomes:
- Plant-the-failure result:
- Platform/API evidence:
- Deviations from plan:
- Residual unknowns/limitations:
- Next phase:

2026-08-30 - planning audit complete; P0 decisions pending

  • Start/end repository commit: 1cc9282546224a263ff5885db12b583b8ad10aae; no product source or release state changed during plan preparation.
  • External audit: all 401 lines read; SHA-256 4c81aefa04e1345f2f0b09d0618c363069dba52d6d2c750f3b2b00ad34e8ed38.
  • Confirmed product facts: scope disconnect, 14-finding noisy self-scan, Node RHS wildcard bug, numeric token-count redaction and missing pre-publication signature gate.
  • Confirmed platform facts: no main protection, no rulesets, no environments, ten open CodeQL alerts, Dependabot alerts/security updates disabled, secret scanning and push protection enabled.
  • Issue inventory: Issues 1/2/5 closed with regressions; 3/4/6/7 open. Issue 3's support premise and Issue 7's secret-scanning premise are stale relative to current repository facts.
  • Workflow evidence: runs 33265040656 and 32980990347 fail on the same public-state assertion; older v1 promotions show the same failure class. The audit's race explanation remains unproved.
  • Focused checks: in-memory source audit reproduced 14 findings; evidence sanitizer reproduced numeric usage.tokens loss; official Node documentation confirms all RHS wildcard instances are replacement sites.
  • Residual state: D1-D5 require owner decisions. No implementation phase has begun.

2026-08-30 - P0 product and governance choices approved

  • Start/end repository commit: 1cc9282546224a263ff5885db12b583b8ad10aae; only this plan changed and no product or GitHub setting was mutated.
  • D1: restricted scope is a file-read boundary.
  • D2: local evidence-only suppression may omit owner/expiry; a suppression affecting CI, release or an external adapter requires both.
  • D3: minimum main/tag protection and a release environment are authorized, with no artificial second-reviewer requirement and an explicit solo-maintainer bypass.
  • D4 rollout: vulnerability alerts, Dependabot security updates and a blocking pull-request dependency-review gate are authorized. Signal owner, gate authority, private escalation and SLA acceptance remain an explicit ownership sub-gate before live enablement.
  • D5: checksum-pinned ShellCheck is included; no code-coverage percentage gate is authorized.
  • P0 result: product semantics, ownership fields and rollout choices are frozen. P1-P8 may start in the required order.
  • Next phase: P1 plants focused failing contracts without changing release or GitHub settings.

2026-08-30 - D4 ownership sub-gate approved; execution authorized

  • Signal owner, update owner and gate authority: @parousia8888.
  • Private escalation: the existing private process documented by SECURITY.md.
  • Triage targets: one business day for a HIGH secret and three business days for a dependency finding.
  • Authorized rollout: vulnerability alerts, Dependabot security updates and a blocking pull-request dependency-review gate after focused and live gates pass.
  • Remaining owner decisions: none. Implementation is authorized through verified v0.8.1 public release and signed v1 promotion.

2026-08-30 - P1 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; changes remain uncommitted until the bounded P2-P9 implementation stack is internally coherent.
  • Finding/Issue/alert IDs addressed: planted contracts for C-03, C-04, C-05, C-07, C-08 and the P3 adapter boundary; no defect was marked fixed in this phase.
  • Files and behavior changed: added focused assertions in evidence-writer, js-ts-module-graph, external-adapters, v081-scope-suppression-contract and v081-release-workflow-contract.
  • Focused pre-fix outcomes: evidence writer failed with actual tokens: '[REDACTED]'; module graph failed with actual resolution null; scope failed because src/private/excluded.js remained in findings; Checkov restricted scope returned adapter_internal_error; Release workflow failed at the missing workflow_dispatch assertion; suppression run remained exit 1 with an active HIGH.
  • Plant-the-failure result: all five failure classes were caused by the intended v0.8.0 behavior, not syntax errors or unavailable fixtures. The external fixture printed the unexpected full-scope argument/evidence state, and the Release assertion printed the tag-push workflow.
  • Platform/API evidence: none; no GitHub settings or refs changed.
  • Deviations from plan: the trusted-attacker tag fixture and pending-promotion fixture remain paired with P7 because they require the verifier/state-machine interface P7 introduces. Their public workflow preconditions are already planted here.
  • Residual unknowns/limitations: passing these assertions will not prove scanner precision or hosted GitHub policy enforcement.
  • Next phase: P2 canonical scope implementation.

2026-08-30 - P2 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; implementation is still uncommitted and locally reviewable.
  • Finding/Issue/alert IDs addressed: C-03 built-in half and A-01; Issue mapping remains open until documentation and hosted evidence close.
  • Files and behavior changed: added scripts/lib/audit-scope.mjs; normalized and validated roots, basename exclusions, mandatory engine exclusions, physical containment, governing inputs and the execution digest; wired the policy into traversal, Git tracked-env pathspec/post-validation, route/access inputs and diff snapshots; expanded schema limits and scope traversal evidence.
  • Focused commands and exact outcomes: audit-scope, source-coverage-ledger, js-ts-source-audit, incremental-source-audit and scope-target-validation all exited 0; git diff --check exited 0. The combined v0.8.1 contract passes its source-root, exclusion, tracked-env, route and diff assertions and stops later at the still-unimplemented suppression.
  • Plant-the-failure result: the same combined contract failed before P2 because the excluded finding remained present; after P2 it advances through every scope assertion. Omitting scopeBoundary retains the documented default full-scope behavior.
  • Platform/API evidence: none; this phase was network-free.
  • Deviations from plan: a missing or invalid custom source root currently stops before report creation with a non-zero scope error. It is fail-closed but does not yet emit an unknown report; that distinction is retained as a documented P9 limitation unless a narrow report path is added.
  • Residual unknowns/limitations: external adapters do not yet consume the policy; pre-v0.8.1 custom baseline compatibility needs its P9 contract wording and test.
  • Next phase: P3 external adapter scoping.

2026-08-30 - P3 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; the bounded implementation remains uncommitted pending the coherent P5-P9 stack.
  • Finding/Issue/alert IDs addressed: C-03 external-adapter half. No adapter result was upgraded from unavailable to completed merely because a selected scope could not be represented.
  • Files and behavior changed: Checkov now receives an exact eligible Dockerfile/workflow list; OSV receives admitted or governing lockfiles only; working-tree Gitleaks and Opengrep use private path-preserving scoped snapshots; restricted Gitleaks history returns unknown / history_scope_not_supported; report adapter metadata records scopeMode.
  • Focused commands and exact outcomes: node test/external-adapters.test.mjs exited 0 and covered all four adapter families, restricted inputs, unexpected paths, missing tools, failures and gate acknowledgement. node test/real-adapters.test.mjs recorded the pinned binaries as unavailable locally rather than claiming a pass; the real pinned run remains a P11 hosted requirement.
  • Plant-the-failure result: the P1 restricted Checkov fixture failed before P3 with adapter_internal_error because the full-scope argument contract was still used. It now reaches completed/not-applicable coverage with scopeMode=governing_inputs; the snapshot fixtures fail if excluded marker files are copied.
  • Platform/API evidence: none; fake adapters were local and network-free.
  • Deviations from plan: Gitleaks history is deliberately unavailable under restricted scope rather than post-filtered. This is the planned fail-closed outcome, not an implemented history filter.
  • Residual unknowns/limitations: exact behavior of the pinned real binaries remains to be proved by the hosted Ubuntu/Node 22 job in P11.
  • Next phase: P4 suppression, report and baseline integration.

2026-08-30 - P4 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; changes remain local and no public gate or release state changed.
  • Finding/Issue/alert IDs addressed: C-04 disposition half and the suppression contract required by Issue 7. Evidence states and finding fingerprints were not redefined.
  • Files and behavior changed: added scripts/lib/suppressions.mjs; accepted only a bounded, subject-bound, non-symlink JSON file with exact adapter/rule/path/fingerprint entries; added expiry and local-versus-gated governance; retained suppressed findings in v3 JSON, Markdown, HTML, SARIF and JUnit; added active/suppressed summaries; made the threshold gate ignore only valid suppressed findings while malformed suppression evidence returns exit 3.
  • Focused commands and exact outcomes: node test/v081-scope-suppression-contract.test.mjs, node test/report-v3-contract.test.mjs and node scripts/check-json-schema-contracts.mjs exited 0. The contract covered path/rule/fingerprint drift, expiry, malformed and symlink files, unknown/evidence-integrity findings, local owner/expiry omission, gated and external governance, renderer agreement and unchanged baseline identity when suppression is added or removed.
  • Plant-the-failure result: replacing the exact fingerprint predicate with true failed at the drift assertion (suppressed observed, active expected). Disabling the expiry predicate made the expired run exit 0 instead of 1 and failed the gate assertion. Both mutations were restored, and the same focused test then exited 0.
  • Platform/API evidence: none; this phase was network-free.
  • Deviations from plan: node test/evidence-writer.test.mjs still fails only at the already-planted P6 numeric usage.tokens assertion. That defect is not marked as a P4 regression or pass.
  • Residual unknowns/limitations: a suppression remains an accepted policy disposition, not proof that the matched condition is safe. No broad directory/rule allowlist exists.
  • Next phase: P5 production-only repository self-audit and public alert-disposition surface.

2026-08-30 - P5 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; work remains local and no GitHub alert was dismissed in this phase.
  • Finding/Issue/alert IDs addressed: C-04 self-audit half; C-06 public disposition surface; historical regression evidence for Issues 1, 2 and 5; ownership text for Issue 7.
  • Files and behavior changed: added versioned .github/self-audit-policy.json, exact governed .github/self-audit-suppressions.json, no-network .github/scripts/run-self-audit.mjs, a dedicated CI job with report artifact, clone-like self-audit regression and docs/code-scanning-dispositions.md; updated alert and false-positive policy with the approved owner/SLA and exact suppression semantics.
  • Focused commands and exact outcomes: node test/repository-self-audit.test.mjs exited 0; the actual repository report retained one suspected MEDIUM rule-registry finding as suppressed, reported zero active and zero unknown findings, scanned with network=false and recorded test, examples, docs/adoption and docs/releases exclusions. Crawler range, AWS permission and sitemap entity/CDATA regressions all exited 0. The P4 suppression contract and git diff --check also exited 0 after the internal policy-path addition.
  • Plant-the-failure result: a clone-like fixture planted rejectUnauthorized: false in the production-scoped .github tree and the self gate exited 1; an invalid-encoding JS file exited 3 with active unknown evidence. The intentionally vulnerable copies under excluded test/example and adoption/release directories did not enter findings and remained counted in coverage.
  • Platform/API evidence: the live CodeQL API returned alerts 1-7 and 9-11 open plus alert 8 fixed. Their rules, paths, current classification, evidence and revisit conditions are recorded in the public ledger. No dismissal API was called before that ledger existed.
  • Deviations from plan: the published generated parser under scripts/vendor is inside the scope, but the built-in JS detector records it as generated_or_minified_source rather than parsing it; its two paths remain visible in coverage. The repository self-audit uses an internal versioned suppression path so ordinary user audits keep the root-file convention and subject binding.
  • Residual unknowns/limitations: live CodeQL dismissals wait for P6 outcomes and P8 API mutation; the self-audit is a bounded built-in static check, not repository safety evidence.
  • Next phase: P6 module graph and evidence-redaction corrections.

2026-08-30 - P6 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; the bounded implementation remains local and no tag, release or GitHub setting changed.
  • Finding/Issue/alert IDs addressed: C-05, C-07, A-02 and A-03; the corresponding CodeQL alert dispositions remain a P8 platform action after the trusted release workflow is locally proved.
  • Files and behavior changed: Node package-export patterns now replace every right-hand-side * literally, including captured paths containing $ or /; TypeScript aliases retain their validated one-wildcard contract and literal replacement; conditional-export traversal considers all object branches but returns ambiguous evidence when supported conditions resolve to different files; finite scalar usage counters under an explicit key allowlist remain numeric, while token strings, arrays, credential keys and non-finite values remain redacted.
  • Focused commands and exact outcomes: node test/js-ts-module-graph.test.mjs, node test/evidence-writer.test.mjs, node test/js-ts-access-path.test.mjs, node test/js-ts-route-authorization-audit.test.mjs and node test/route-access-path-coverage.test.mjs all exited 0. The repository self-audit also exited 0 with its exact suppression still valid, zero active findings and zero unknown findings.
  • Plant-the-failure result: temporarily restoring first-only Node wildcard replacement made the repeated-RHS fixture fail with resolution null; temporarily removing the scalar usage-counter allowlist made usage.tokens become [REDACTED] and failed its exact assertion. Both mutations were restored and both focused tests returned to exit 0.
  • Platform/API evidence: none; this phase was network-free.
  • Deviations from plan: the first redaction run exposed an additional credential boundary: tokens: [101, 202] was recursively retained. The array branch now redacts secret-key arrays as a whole, and the focused test proves that the usage exception applies only to finite scalars.
  • Residual unknowns/limitations: conditional export identity remains unavailable when conditions select different existing files; runtime reachability is not inferred. Numeric usage preservation is intentionally key-allowlisted rather than a general exemption for token-like fields.
  • Next phase: P7 trusted-main release workflow, signer verification and pending v1 lifecycle.

2026-08-30 - P7 complete

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; all work remains local, and no public ref, Release, package, environment or repository rule changed in this phase.
  • Finding/Issue/alert IDs addressed: C-02 and C-08; C-01's live environment/ruleset half remains P8. The release workflow now has the local contract required before those settings are enabled.
  • Files and behavior changed: release publication is a main-only manual dispatch with explicit version/tag; a read-only job sources its verifier and signer allowlist from trusted main, checks an annotated signature, exact commit, candidate metadata and six exact hosted checks before npm ci; a release-environment job alone has publication/attestation permissions; a read-only job re-downloads and verifies public assets. Generic CI is branch/PR scoped to main.
  • Files and behavior changed for v1: docs/release-state.json now distinguishes pending and final; an exact transition CLI records the expected source and prior tag object; pending and final public-state verification are separate; the Action consumer has immutable-only, promotion and final phases under one non-cancelling concurrency group, and finalization reuses the exact successful promotion-run artifact instead of rerunning consumers.
  • Focused commands and exact outcomes: release candidate verifier, Action promotion state, release-state, release-promotion, release-trust-boundary and v0.8.1 workflow-contract tests all exited 0; check-release-contract, check-document-contract, YAML parsing, git diff --check and the repository self-audit exited 0.
  • Plant-the-failure result: temporarily bypassing git verify-tag made the wrong-signer fixture be accepted and failed the verifier test; allowing pending state through final verification failed the release-state test; giving verify-and-build contents write and changing CI away from main failed the workflow contract. All four mutations were restored and the focused suite returned to exit 0.
  • Platform/API evidence: a read-only GitHub query confirmed the actual required check names on the baseline commit: repository-self-audit is new for the candidate, alongside four matrix jobs and analyze; no mutation API was called.
  • Deviations from plan: final v1 evidence uses two serialized workflow dispatches. The promotion run executes the Action consumers while state is pending; the final run downloads that exact successful artifact and publishes the durable record after state finalization, avoiding duplicate consumer execution.
  • Residual unknowns/limitations: local YAML parsing and contract tests do not prove GitHub accepts or enforces the workflow/environment permissions; that becomes hosted P11 evidence. Two Git refs remain non-transactional, and the prior-object lease is the control for the movable alias.
  • Next phase: P8 live GitHub governance, alert dispositions, dependency gate and pinned ShellCheck.

2026-08-30 - P8 checkpoint; public-alert closeout waits for P11

  • Start/end repository commit: start 1cc9282546224a263ff5885db12b583b8ad10aae; implementation remains local. GitHub settings changed, but no source ref, release, package or release tag changed.
  • Live platform changes and readback: Dependabot vulnerability alerts and security updates are enabled; main rejects force-push/deletion and requires strict CodeQL, four Node/OS CI matrix, repository-self-audit, ShellCheck and pull-request dependency-review checks; administrator bypass is explicit for the solo maintainer. Active tag rulesets block update/deletion of v0.* and v1 unless the administrator bypass is used. The release environment accepts protected branches and has no fabricated second reviewer.
  • Local gate evidence: dependency review is pinned to Action commit 3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 and blocks moderate or higher changes. Changing its threshold to critical failed test/v081-platform-governance-contract.test.mjs. A checksum-pinned ShellCheck v0.11.0 install verified the macOS arm64 archive; a planted unused variable produced SC2034 and exit 1, and the restored warning-level run exited 0. The platform contract and git diff --check exited 0.
  • First Dependabot inventory: 32 open alerts, all at examples/quickstart/before/package.json (2 critical, 10 high, 16 medium, 4 low), plus generated PR 8. The old Next 15.0.0 pin is not a required vulnerable condition. The candidate aligns both quickstart manifests at 16.3.3, retains the intentional missing before lockfile, creates a real after lockfile and returned zero point-in-time npm audit --omit=dev findings. A planted mismatch between before/after versions failed the platform contract and was restored.
  • Public records: sanitized readback is in docs/releases/v0.8.1-platform-governance.json; Issues 3, 6 and 7 received evidence comments. Issues 3 and 6 remain open for real WSL2 and coverage research. Issue 7 remains open until hosted dependency review and post-push alert/PR readback complete.
  • Ordering deviation: CodeQL alerts 1-7 and 11 are not dismissed while their public ledger exists only locally. Alerts 9/10 remain open production alerts and are never dismissed as fixtures. P9 and P10 may prepare the exact candidate; after P11 publishes the ledger, P8 closeout performs the approved test/fixture dismissals, closes superseded dependency state, re-reads all API facts and only then marks P8 complete. This preserves the plan's no-dismissal-before-public-evidence gate.
  • Residual unknowns/limitations: new required checks have not yet run on the candidate; dependency alerts cannot close before the manifest reaches main; an npm registry audit is point-in-time evidence, not a permanent no-vulnerability claim.
  • Next phase: P9 public documentation and distribution synchronization, with P8 remaining in progress until the P11 closeout described above.

2026-08-31 - P9 complete

  • Start/end repository commit: start and end base 1cc9282546224a263ff5885db12b583b8ad10aae; the coherent P2-P9 implementation remains local and uncommitted. No public ref, package, release or GitHub setting changed in this phase.
  • Finding/Issue/alert IDs addressed: public contracts for C-02 through C-08, A-01 through A-05 and the approved D1-D5 boundaries. No detector family or evidence state was added.
  • Files and behavior documented: English/Chinese README and tutorial now explain the canonical file-read scope, exact visible suppression, adapter scope modes and restricted-history unknown; compatibility, limitations and adapter protocol expose abort/partial boundaries; capability, alert/false-positive, roadmap, changelog, AI/Skill maps and public contract describe production self-audit, module/redaction corrections and trusted-main/pending-final release behavior.
  • Distribution changes: docs/false-positive-policy.md is included in npm and installed Skill payload allowlists. Engineering/adoption plans and platform-governance evidence remain outside the runtime payload.
  • Focused commands and exact outcomes: capability matrix check exited 0 and reported 29 total capabilities, 11 stable detection categories and zero planned detection; document, product, public-surface, release and distribution contracts each exited 0; relevant JSON parsing and git diff --check exited 0.
  • Plant-the-failure result: not separately required for prose-only P9 claims; existing public, capability, release and distribution contract checks machine-bind headings, categories, evidence paths, release language and payload membership. Silent product regressions remain covered by the planted P1-P8 tests recorded above.
  • Platform/API evidence: none added. Documentation retains hosted checks, public package, attestation and v0.8.1 consumer state as pending; current v0.8.0 public facts remain separate.
  • Deviations from plan: docs/public-contract.json records v0.8.1 as nextSourceCandidate while VERSION and currentSourceRelease remain v0.8.0 until the atomic P10 version freeze. This keeps P9 contract checks green without presenting an unpublished candidate as the current release.
  • Residual unknowns/limitations: WSL2 remains unsupported; invalid custom roots can abort before a report artifact; restricted Gitleaks history remains unknown; self-audit is bounded evidence; the solo-maintainer administrator bypass is not independent review.
  • Next phase: P10 atomic v0.8.1 version/evidence freeze and the single full local candidate gate.

2026-08-31 - P10 complete

  • Start/end repository commits: version and implementation surfaces froze in 142c7ac7a7f42fcf0ad9d17bbd31735943542ab8; the fixed-project evidence refresh and single full local gate ran on b55e8a170f72378e742cfbe34adcb9ac00e06c2e. No v0.8.1 tag, GitHub Release, npm publication or v1 movement occurred.
  • Version and candidate surfaces: VERSION, npm/package lock, Claude plugin/marketplace, Action, capability/public contracts, changelog and release evidence name v0.8.1 together. Published v0.8.0 source facts remain unchanged until each public v0.8.1 object is observed.
  • Full local gate: npm run check exited 0. It recorded 88 passing test files, zero failures and one optional real-adapter skip; prerequisite surfaces recorded three passed, zero failed and one skipped. Bash 3.2 smoke, lint, schema, generated-file, public, release and distribution contracts passed. No required check was failed or marked not-run.
  • Skill validation: the first system-Python invocation was unavailable because PyYAML was absent and was not called a pass. uv run --no-project --with pyyaml python /Users/kenn/.codex/skills/.system/skill-creator/scripts/quick_validate.py . then returned Skill is valid! from an isolated dependency environment without changing project dependencies.
  • Package/SBOM evidence: npm pack --dry-run --json recorded 221 files, 672,551 packed bytes, 2,821,340 unpacked bytes, SHA-1 2c9e06be7bd555a05fd8a8d8d908d3f54506f1d8 and integrity sha512-SUonYq1kXt8/Noz0yR3qubR7rhI+ob70heTf5xJPJNMFNdC5eUP4c3GvQ42IsTPozNHCyO3/O8Z2J2sRlffu3w==. The candidate SPDX 2.3 SBOM at /tmp/wass-v0.8.1-candidate.spdx.json has SHA-256 fb1b1762efc849f77310fbbb8bc5aed795eb87210dc1def36851bd3b02aeda46 and remains outside the tree.
  • Fixed-project refresh: Linkwarden returned 278 findings and exit 3/incomplete; Healthchecks 149 and exit 0/complete; Open WebUI 162 and exit 3/incomplete; Uptime Kuma 122 and exit 3/incomplete; Mealie 37 and exit 0/complete. All pinned checkouts remained clean. Gitleaks 8.30.1 used digest ba52fb1b...e84f; OSV-Scanner 2.5.0 used digest fff5a2e3...da2. The shortened digests are journey log labels, not release checksum claims; exact adapter provenance remains in generated evidence.
  • Evidence-only closeout: this P10 record is the only post-gate source delta. Only document/release contracts and whitespace are rerun locally; P11 executes the complete matrix, CodeQL, repository self-audit and pinned real adapters on the exact pushed evidence commit.
  • Residual unknowns/limitations: local optional real-adapter evidence remains skipped rather than passed; the candidate SBOM is not yet the signed public asset; no hosted branch/rules/environment, npm provenance, installer, Action consumer or public-object claim is made.
  • Next phase: push the evidence-only candidate to main without a tag and complete P11 exact-commit hosted verification, then close the deferred P8 live alert/Issue work.

2026-08-31 - P8 complete

  • Hosted governance identity: the public ledger reached main in candidate commit 66a549c1248cbf68d7f470443c3f072f5b75374c before any CodeQL dismissal. The post-candidate sanitized readback was added to docs/releases/v0.8.1-platform-governance.json without replacing the original 32-alert snapshot.
  • CodeQL disposition: candidate analysis closed production alerts 9 and 10 as fixed; neither was dismissed. Alerts 1-7 and 11 were re-read at their documented test/fixture paths, then dismissed as used in tests with the public revisit conditions retained. A second API read returned zero open CodeQL alerts.
  • Dependency state: the 32 open Dependabot alerts under the quickstart before fixture fell to zero after its manifest reached main; generated PR 8 closed without merge. This is point-in-time platform evidence, not a permanent dependency-safety claim.
  • Hosted PR gate: old PR 8 predated the new dependency-review job and could not prove its supported event path. Temporary PR 9 therefore used an empty commit and zero file diff. The full-SHA-pinned Action passed in run 33319628174, job 99279204655; duplicate matrix/CodeQL work was cancelled, the PR closed without merge and the temporary local/remote branch was deleted.
  • Repository controls: strict required checks, no main force-push/deletion, active immutable-v0 and movable-v1 tag rulesets, and protected-branches-only release environment were re-read. The administrator bypass is retained for the approved solo-maintainer minimum and does not create independent review.
  • Issue state: Issue 7 received the exact hosted evidence and closed as completed. Issues 3 and 6 remain open because WSL2 and an evidence-based coverage threshold remain unproved; neither was converted into a v0.8.1 pass.
  • Residual limitations: dependency review was proved on a no-diff PR; the planted local contract, not the hosted probe, proves the moderate threshold text. GitHub settings do not protect against maintainer account compromise.
  • Next phase: complete and record P11 exact-commit hosted candidate evidence.

2026-08-31 - P11 complete

  • Candidate identity: 66a549c1248cbf68d7f470443c3f072f5b75374c was pushed to main without creating v0.8.1, publishing npm or moving v1.
  • CI evidence: run 33319363473 concluded success. All macOS/Ubuntu Node 22/24 jobs passed lint, tests and shell smoke; Ubuntu/Node 22 also installed checksum-pinned Gitleaks 8.30.1 and OSV-Scanner 2.5.0 and passed the real-adapter fixtures. ShellCheck and repository self-audit passed; dependency-review was correctly skipped on the unsupported push event.
  • CodeQL evidence: run 33319363476 concluded success on the same commit and produced the P8 alert outcomes above. No failed hosted check was rerun or hidden.
  • Self-audit artifact: its checksum manifest verified. JSON recorded zero active, zero unknown and one visible suppressed MEDIUM finding; report.json SHA-256 is b3028306b46edb2ba2e26d584f68d9b5bd925e55d75752bd9d3d83e774e74f46. The suppression is a policy disposition and the report is not repository-safety evidence.
  • Governance/alert evidence: main, tag rules, release environment, Dependabot, CodeQL, Issues 3/6/7 and PRs 8/9 were re-read as recorded in P8. No unavailable setting was marked passed.
  • Evidence-closeout boundary: this P8/P11 documentation commit is a bounded, evidence-only delta. It must receive its own exact hosted checks before tagging. The trusted-main release workflow independently requires the tag source, dispatch SHA, main SHA and six required successful check SHAs to agree, so the earlier run cannot authorize a changed release source.
  • Residual limitations: immutable signature, public assets/attestations, npm provenance, verified install, full-SHA Action consumption and signed v1 promotion remain pending P12.
  • Next phase: after exact hosted checks pass on this evidence commit, sign and publish the immutable v0.8.1 release, verify npm/install/Action, then perform the pending/final v1 promotion.

2026-08-31 - P12 immutable release and npm checkpoint

  • Final immutable source: 6e581adcac7a0433ec6428d8080d20761dfc3a93; exact-source CI 33319821767 and CodeQL 33319821731 passed before publication.
  • Signed/public release: annotated tag object 69ed5f3dac996e44df62dbd7b5137eb97ef19e6b peels to the exact source and verifies against .github/release-signers. Release workflow 33320019069 published release ID 379322728; all four public asset digests, the 569-entry manifest and GitHub attestation verified.
  • npm: trusted-publishing workflow 33320091098 published web-app-security-skill@0.8.1 with SLSA provenance and gitHead equal to the release source. All 221 package files matched the signed source archive byte for byte; fresh-cache npx ... version returned 0.8.1.
  • Installer trust: commit 4471a347156ed319a4d4f1262d5db5b508ee8d0d added only the observed v0.8.1 asset identities and changed the verifier default. Its CodeQL run 33320234387 passed; CI 33320234456 correctly failed because the still-v0.8.0 public state disagreed with the new verifier. The state contract blocked a partial transition rather than silently accepting it.
  • Current boundary: stableAction and signed v1 still identify v0.8.0. No v0.8.1 Action or verified-installation claim is made until bootstrap and consumer gates pass.
  • Next step: synchronize observed Release/npm/installer facts, obtain a green exact commit, pin bootstrap to that verifier blob, then run clean-room installation and the pending/final Action promotion lifecycle.

2026-08-31 - P12 public-state and bootstrap checkpoint

  • Public-state synchronization commit 0e53aaeb962d51f245b909de803e3fbd12c06b1d passed CI 33320577554 and CodeQL 33320577552; the four platform/Node jobs, real adapters, ShellCheck and production-scope self-audit all completed successfully.
  • The verifier blob at that exact green commit has SHA-256 d5e9f4ce50d9c38ef3502d512af1f342e80edd96844351d6134594de75b2edb8. The bootstrap, release contract and bilingual verification guide now pin the same commit and digest.
  • The v0.8.1 release-state migration test now models immutable publication preceding signed v1 promotion, using a verified annotated tag object in its pending-state fixture instead of assuming the published version and stable alias always advance atomically.
  • Current boundary: the updated bootstrap has not yet passed its own hosted checks or an isolated attestation-required all-target installation. v1 remains unchanged at v0.8.0.
  • Next step: pass focused bootstrap/release tests and exact hosted checks, then execute the isolated public installer before Action promotion.

2026-08-31 - P12 public entrypoint and isolated-install checkpoint

  • Bootstrap identity: commit 0d488226ac55036b8871ff12b5572e697ec37bb7 pins verifier commit 0e53aaeb962d51f245b909de803e3fbd12c06b1d at SHA-256 d5e9f4ce50d9c38ef3502d512af1f342e80edd96844351d6134594de75b2edb8; the bootstrap blob itself has SHA-256 0b9c43d22c886f1f5394613800701eeeb1919a858168c5ca678f227ba0306c95. Exact-source CI 33320776213 and CodeQL 33320776165 both succeeded.
  • Isolated public install: a fresh temporary HOME ran the pinned public bootstrap with explicit --version 0.8.1 --attestation required --target all. GitHub attestation verification passed; Claude, Codex and CLI surfaces installed as v0.8.1; the installed CLI returned Web App Security Skill 0.8.1. An earlier attempt without authenticated gh evidence failed as required and was not counted as a pass. No credential value was written to the log.
  • Public entrypoint correction: the bilingual README and verified-installation guides now pin the bootstrap commit/digest above and use v0.8.1 asset names. Immutable Action examples and the immutable-only consumer now pin release source 6e581adcac7a0433ec6428d8080d20761dfc3a93; v0.8.0 remains named only as the current moving v1 target until promotion completes.
  • Regression gate: test/v081-release-workflow-contract.test.mjs now requires the exact v0.8.1 immutable source and rejects the prior v0.8.0 source. The focused workflow, release-contract, release-state, bootstrap and document checks exited 0; Ruby parsed the changed workflow and git diff --check exited 0. A first attempt to call nonexistent scripts/check-yaml.mjs failed with MODULE_NOT_FOUND; it was a mistaken validation command, not a product result, and was replaced by the repository-available Ruby YAML parse.
  • Current boundary: this public-entrypoint delta is local until its exact commit passes hosted CI and CodeQL. v1 still peels to v0.8.0 and no promotion state has begun.
  • Next step: commit and push this bounded delta, wait for exact-source hosted checks, rerun the published README bootstrap once, then dispatch the immutable-only Action consumer.

2026-08-31 - P12 immutable consumer and pending-promotion checkpoint

  • Public-entrypoint commit 1e23b1bce3c59d481734c30785bd7085498ace02 passed CI 33321240947 and CodeQL 33321240956. The CI result includes four Node/OS jobs, production self-audit, ShellCheck and the Ubuntu/Node 22 pinned real-adapter fixtures; dependency review was correctly skipped for a push event.
  • The exact published README bootstrap was downloaded from commit 0d488226ac55036b8871ff12b5572e697ec37bb7, matched SHA-256 0b9c43d22c886f1f5394613800701eeeb1919a858168c5ca678f227ba0306c95, then installed explicit v0.8.1 into a fresh HOME with --attestation required --target all. Attestation passed; all three surfaces installed; the CLI returned Web App Security Skill 0.8.1.
  • Immutable consumer run 33321407515 succeeded. It consumed Action source 6e581adcac7a0433ec6428d8080d20761dfc3a93 by full SHA and verified the bounded route/access artifact. The moving v1 consumer and final-state jobs were skipped by the immutable-only phase.
  • Promotion lease: remote signed tag object 3e44c123d45f5fc06fa437fe1fbd58a71c5aaaa8 still peeled to v0.8.0 source 119cbcc7f8d327482df8abfa50a4af0b69fcceee and verified against the signer policy. The state transition CLI recorded pending v0.8.1 source 6e581adcac7a0433ec6428d8080d20761dfc3a93 plus that exact prior object. v1 has not moved.
  • Pending-gate correction: the first focused run showed test/release-state.test.mjs still required the live file to be final even though the production validator accepted the designed pending state. The test now accepts only the two exact v0.8.1 lifecycle records: old stable source plus exact pending version/source/prior object, or new stable source plus cleared final state. Its isolated repository exercise covers old signed alias, pending alias, new signed alias, final and stale-alias rejection. Release-state and transition tests then exited 0.
  • Local-execution deviation: one public-install command was rejected before process start because its cleanup trap used a locally prohibited deletion form. The same verification was rerun without cleanup; its temporary evidence paths were retained. This is not an installer failure.
  • Next step: publish and host-verify the pending state commit, then create and locally verify a new signed annotated v1 object and push it only with the exact prior-object lease.

2026-08-31 - P12 signed-alias promotion checkpoint

  • Pending source: commit 33884e8b6b12f9ad572fe69a348e9879016ca524 passed CI 33321543906 and CodeQL 33321543856, including all four matrix jobs, real adapters, production self-audit and ShellCheck. No tag moved before these checks succeeded.
  • Exact alias mutation: signed annotated tag object c7482458f0ba9a86c1531651af9b64be61286e70 peels to release source 6e581adcac7a0433ec6428d8080d20761dfc3a93. Local signer-policy verification passed; GitHub returned verified=true and reason valid. The push used force-with-lease against exact prior object 3e44c123d45f5fc06fa437fe1fbd58a71c5aaaa8; the approved administrator bypass was recorded.
  • Consumer evidence: promotion run 33321731609 succeeded. It consumed the immutable source and signed v1, verified passive success, explicit authorization rejection, no active-probe request, Release/npm identities, pending public state and an attestation-required all-target install. Its 90-day artifact records the pending commit and both consumer outcomes.
  • Final transition: action-promotion-state.mjs finalize accepted only the same expected source, changed stableAction.sourceCommit to the release source and cleared pending-only fields. The durable final live-verification record is not yet claimed.
  • Final-fixture correction: after the real local v1 ref moved, the release-state test could no longer obtain the historical old object by resolving current v1. Its isolated old-state model now uses the signed immutable v0.8.0 tag object and asserts that it peels to the exact prior stable source; the live pending-state branch still requires the actual historical v1 object.
  • Next step: push and host-verify the final state, dispatch phase=final with promotion run 33321731609, verify its Release asset and then record P12 completion.

2026-08-31 - P12 complete

  • Final tracked state: commit 16c05ac009dc374e9729f3c608e5779546d91e8a records stableAction.sourceCommit=6e581adcac7a0433ec6428d8080d20761dfc3a93 with promotion state final and no pending-only fields. CI 33321898478 and CodeQL 33321898475 both succeeded on that exact commit.
  • Durable verification: final workflow 33322069144 accepted only retained promotion run 33321731609, re-bound it to the finalized tracked state and completed successfully. Its web-app-security-skill-0.8.1.live-verification.json workflow artifact and GitHub Release asset are byte-identical.
  • Release asset: the downloaded JSON has SHA-256 0fae8eaa68bafe35b52e8ed2c3b22b92e49c7b91fc58f9d83e6ed99210f2c6fa, equal to GitHub's recorded sha256: digest. It records state=live_verified, version 0.8.1, release source 6e581adcac7a0433ec6428d8080d20761dfc3a93 and eight verified gates covering assets, tag, GitHub/npm provenance, installer, immutable consumer, v1 consumer and alias state.
  • Final ref check: remote v0.8.1 object 69ed5f3dac996e44df62dbd7b5137eb97ef19e6b and signed remote v1 object c7482458f0ba9a86c1531651af9b64be61286e70 both peel to the release source. GitHub reports the v1 signature verified with reason valid; npm gitHead remains the same source.
  • P12 boundary: v0.8.1 publication is complete. The moving alias and solo-maintainer administrator bypass retain the documented limitations; no precision/recall, repository-safety, WSL2 or independent-review claim was added.

22. Phase tracker

Phase Status Exit artifact
P0 evidence/decisions complete approved plan and decision record
P1 failing contracts complete pre-fix failure ledger
P2 built-in scope complete canonical scope implementation and tests
P3 adapter scope complete adapter scope matrix evidence
P4 suppression complete schema/render/gate/baseline evidence
P5 self-audit complete production-scope self-report and alert ledger
P6 module/redaction complete focused regression evidence
P7 release workflow complete local trust-boundary fixtures
P8 platform governance complete live API evidence and Issue comments
P9 documentation complete synchronized public contracts
P10 local candidate complete exact candidate and test inventory
P11 hosted candidate complete exact-commit CI/CodeQL/self-audit evidence
P12 public release complete immutable release/npm/install, signed v1 and durable live verification

23. Expected residual limitations after v0.8.1

The release may still state all of the following openly:

  • built-in detectors remain bounded static rules, not whole-program taint analysis;
  • a suppression records accepted policy, not proof that a condition is safe;
  • restricted Gitleaks history may remain unavailable if exact path-bounded history scanning is not demonstrated;
  • conditional Node exports may remain partial when runtime conditions select different files;
  • moving v1 is convenient, not immutable; full-SHA consumers remain the strongest pin;
  • a single-maintainer repository cannot provide independent code review by configuration alone;
  • branch/ruleset controls reduce accidental or unauthorized ref mutation but do not prove GitHub account security;
  • WSL2 remains unsupported until Issue 3 obtains a maintained clean environment;
  • CodeQL/test disposition and a clean self-audit do not establish production vulnerability precision or repository safety.