Skip to content

v1.91.270.0 feat(ship): version-less repos, docs-audit record and caps, the frozen-scope paid case, and the review-loop follow-ups - #3487

Merged
capy-ai[bot] merged 18 commits into
mainfrom
capy/version-less-repos-docs
Oct 27, 2026
Merged

capy-ai[bot] merged 18 commits into
mainfrom
capy/version-less-repos-docs

Conversation

@garrytan

@garrytan garrytan commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner
{
  "schema_version": 1,
  "pr": 3487,
  "head": "e78f9beb5b4be0ac80be18f656f754d4a6af0e64",
  "version": "1.91.267.0",
  "base": "main",
  "gate": {
    "remote_gate": {
      "pass": 21964,
      "fail": 0,
      "source": "gstack-pregate --stage tests --remote (Ubicloud, unit + e2e tiers) at tree 740dcf0ca5ab, $0.06"
    },
    "local_pregate": {
      "pass": 7,
      "fail": 0,
      "source": "gstack-pregate --allow-repo-commands at head e78f9beb (tree 740dcf0c): regen fresh, secrets, lanes; 7 checks"
    },
    "typecheck": {
      "pass": 1,
      "fail": 0,
      "source": "bun run typecheck clean; typecheck:test 819 known diagnostics, none new (12d0463, 775d980, 57ac5b0, e78f9be)"
    },
    "free-tests.yml": {
      "pass": 29,
      "fail": 0,
      "source": "pull_request run 40454896943 at e78f9beb, 29 jobs success"
    },
    "windows-free-tests.yml": {
      "pass": 8,
      "fail": 0,
      "source": "pull_request run 40454897085 at e78f9beb, 8 jobs success, 1 skipped (record-durations)"
    },
    "trial_merge": {
      "pass": 5,
      "fail": 0,
      "source": "rule-25 trial merges of e78f9beb against the pooled pins #3434 f45f1ada, #3453 af025a0c, #3507 ef6a1632, #3494 564d3413, #3501 343db9bb: each conflicts on CHANGELOG.md only, plus the ship maxSizeRatio line of test/helpers/carve-guards.ts for #3434, #3453 and #3501 (1.7400 here vs 1.7172 / 1.7172 / 1.7250; the slot re-measure); #3494 and #3501 also conflict with main on NOTICE.md, untouched by this branch"
    },
    "own_case_paid": {
      "pass": 54,
      "fail": 0,
      "source": "ship-frozen-scope-convergence PASS 3/3 at 775d980 ($0.65); the 51 /ship and /review own cases focused at 775d9804: 49/51 ($22.35), ship-docsync-completion and ship-docsync-current red twice (fixture interface; repaired in 2524ec4..57ac5b0, reruns at 2524ec4 $3.94 and 0230fc2 $1.81 red on the next fixture gap each) and PASS 2/2 at 57ac5b08 in round 1 ($2.09); own-case spend $31.53 of the $34 cap"
    },
    "pull_request_checks": {
      "pass": 44,
      "fail": 0,
      "source": "every pull_request check GitHub scheduled at e78f9beb (Free Tests, Windows Free Tests, Version Gate, Quality gate, E2E Evals readiness/route/screen-summary, Windows Setup E2E, Windows Pregate E2E, Skill Docs Freshness, Workflow Lint): 44 pass, 0 fail, 0 pending, 15 skipped (dispatch-only and train-only jobs); mergeStateStatus CLEAN"
    }
  },
  "session_kind": "unattended",
  "pregate": "requires-remote cleared @740dcf0ca5ab (1 checks, current for e78f9beb5b4b)",
  "requires_remote": [
    "free-tests.yml/cso-macos-launcher: https://github.com/garrytan/gstack/actions/runs/40454896943",
    "free-tests.yml/macos-named-regressions: https://github.com/garrytan/gstack/actions/runs/40454896943",
    "windows-free-tests.yml/windows-free-shard: https://github.com/garrytan/gstack/actions/runs/40454897085",
    "pregate.json/remote_gate: remote-gate tree=740dcf0ca5ab tests=21964"
  ],
  "issues": {
    "fixes": [],
    "refs": [
      3504
    ],
    "flakes": []
  },
  "review_loop": {
    "passes": 12,
    "blocking_found": 10,
    "deferred": 0,
    "noted": 43,
    "fixed": 30,
    "scope": "frozen"
  }
}

Second PR of the /ship and /review convergence lane; #3481 (v1.91.256.0) landed, so this one targets main. Everything here is generic: no crew names, configurable repository names. main d9b0d60 (v1.91.267.0) is merged in under the owner's rule-19 grant: CHANGELOG.md through mergeChangelogs (the [Unreleased] entry above main's headings), bin/gstack-doctor-components.sh regenerated from its generator, docs/troubleshooting.md and lib/result-codes-release.ts additive (gstack-pr-wait's two codes beside this branch's three); the branch's diff over main is byte-identical to its diff over the old base except one dropped blank line in troubleshooting.md. DOCS_CAPS_KEY_VERSION stays 1.91.258.0 for the pin; the stamp moves it.

Summary

Repositories without a version source

/ship Step 12 and the CHANGELOG step no longer assume VERSION, package.json#version or CHANGELOG.md. When the head has none of them and the policy names no stamp file, the steps print Version bump: skipped (no version source: <path, reason>) and CHANGELOG: skipped (none at <path>), the PR title is unprefixed, the run log records "version": null, and the receipt records "version": "none" (gstack-ship-receipt write derives it only after VERSION, package.json#version, the stamp files and the CHANGELOG are all absent; read, result and the queue accept it).

Docs audit record and doc caps

gstack-ship-receipt write --docs <json|@file> records docs: { status: updated|current|blocked, scope, exception?: { accepted_by, date, via, reason } } (new lib/ship-receipt-docs.ts). A blocked audit with no owner exception is DOCS_AUDIT_BLOCKED and no receipt is written; with --body, the body must carry the exception line verbatim. A repository may declare docs.caps: [{ path, max_bytes }] in .gstack/ship-policy.json (needs min_gstack_version at or above DOCS_CAPS_KEY_VERSION); gstack-ship-receipt docs-caps [--base <ref>] [--policy <file>] reads the base branch's policy (POLICY_SOURCE_UNAVAILABLE when it cannot), prints one DOCS_CAP: <path> <bytes>/<max> ok|over line per cap and exits 1 on any over or absent file; Step 14.5 runs it before the verification gate and clears a stale .gstack/tmp/docs-audit.json on first entry.

Unattended evidence

docs/unattended.md#ship-evidence names gstack-ship-receipt result (its GSTACK_RESULT line and run directory) as the machine-readable READY evidence, the review_loop counters, the CARRY: lines, and the accepted outside voice on a host without the Codex CLI: a subagent on a different model family, logged as an adversarial-review row with its source and outside status, the unavailable cause on the gstack-outside-voice run: stderr line.

Paid case: ship-frozen-scope-convergence

A behaviour case (gate tier) reusing the ship e2e harness: a fixture with one CRITICAL in the diff and one in untouched code; the actor runs the generated Step 9.4 and repeat decision under review_scope: frozen through the real gstack-review-scope and gstack-review-log binaries. The verdict requires the in-diff fix committed, the untouched file byte-identical and deferred, pass 2 on the range only, exit via decision 4, and REVIEW_LOOP: passes=2 blocking_found=2 deferred=1 fixed=1 scope=frozen. Registered in E2E_TOUCHFILES / E2E_TIERS / E2E_KINDS (+ BEHAVIOR_WHY) and the SDK host list; a free scripted actor test with negative controls (test/ship-frozen-scope-actor.test.ts). The fixture actor's message handling was repaired after the first focused panel (see Eval Results).

Docsync fixture: Step 14.5's own-tree commands (test-only)

The focused paid run of the 51 /ship and /review own cases at the pooled pin left ship-docsync-completion and ship-docsync-current red twice: the actor stopped at the Step 14.5 cap gate because the docsync fixture's closed interface did not declare the section's three own-tree commands (the shared .gstack/tmp exclude line, rm -f .gstack/tmp/docs-audit.json, gstack-ship-receipt docs-caps --base <base>) or the record write, and its repositories had no origin/main for the gate to read. The repair is confined to the fixture (test/helpers/docsync-{interface,observer,fixture}.ts, test/docsync-command-grammar.test.ts, test/skill-e2e-ship-docsync.test.ts): the interface declares exactly those commands (derived from the same freeTextFileBash the section renders, so byte-identical; the ~/.claude/skills/gstack form the section prints is accepted when the fixture's skills dir is under its HOME), every scenario pushes main to a bare remote, the fixture installs lib/ beside bin/ so the gate can load (pinned by a live spawn printing DOCS_CAP: none declared), the record write is housekeeping for read-only audits too, the shared record paths are permitted for every docsWriteFailures caller, and the Write tool's atomic landing of the record (<record>.tmp.<pid>.<12 hex> + rename) is admitted only as the cookie-paired source of a move onto the record that leaves nothing behind. One prose line moved in ship/sections/documentation.md.tmpl: the Entry runs the exclude line before its rm -f, and the caps paragraph was tightened to hold the ship parity union at 1.7400.

Follow-ups from #3481's review notes

  • gstack-ship-receipt carry: probes git ≥ 2.39 before patch-id --verbatim and refuses older gits with RECEIPT_GIT_TOO_OLD naming the installed version; a failing patch-id is RECEIPT_CARRY_REFUSED with git's stderr, never a carry; the per-path walk covers branch-touched paths only and names at most CARRY_NAMED_PATHS (20); stampOnlyText digit-bounds the version replacement.
  • gstack-review-scope defer: gh repo view receives the repository positionally, so the visibility read works under --repo; DEFERRED_SEARCH_LIMIT = 200 is named and an exactly-full page is reported as truncated.
  • Step 11 late defers are logged under skill review-late-defer (LATE_DEFER_SKILL): their deferred findings count in review_loop, but they are not passes.
  • The specialist and Red Team prompts scripts/resolvers/review-army.ts renders for /ship carry their diff base as a literal sha (DIFF_BASE=<diff-base>: the merge base on pass 1, RANGE_BASE from pass 2 on), never a shell variable; Step 9.4 runs the cap check before any edit (0. Scope → 1. Cap, then classify → 2. Auto-fix) and names its scratch files under .gstack/tmp/.
  • Reviewer fan-out (--review-fanout auto|serial|parallel, /ship only): under auto, fewer free subagent slots than specialists means batches of the free-slot count; docs/review-policy.md#reviewer-fan-out.

Also in this PR

Gate integrity

No threshold, timeout, trial count or case kind changed. The ship parity maxSizeRatio in test/helpers/carve-guards.ts moves 1.7150 → 1.7400 (measured 326,437 / 187,706 = 1.7391, held after the pass-1 fixes by tightening prose rather than re-pinning); test/fixtures/module-size-ratchet.json records the two new modules. Registry-count tests (eng-finding-retry-budget 110 → 111 discovered files, paid-run-manifest deriving trial counts, ship-skip-selection, exercised-map) follow the new case; test/review-fix-range.test.ts follows the literal-diff-base sentences.

Test Coverage

Coverage: 70% value-weighted (83% including 5 weakly covered paths) over 30 new code paths at the Step 7 audit (pass 1 of 2; the 60 ≤ 70 < 80 gate was answered under the unattended rule: generation restricted to true gaps).
Test value: 1 test written (the carry patch-id refusal, test/gstack-ship-receipt-docs.test.ts), 0 rejected by the authoring gate, 0 existing tests extended, 5 paths weakly covered (weak = ★, gate-failing or unrated); 4 of the 5 gaps were then covered by the pass-1 fix tests (--base resolution, shared-leaf and hyphen prose, package.json / stamp_files / changelog fallbacks, docs-caps base policy).
Proposed strengthening, not written: the prompt-token tests for the review-army and documentation templates assert that sentences exist (DIFF_BASE=<diff-base>, rm -f .gstack/tmp/docs-audit.json, docs-caps --base <base>) and do not exercise an agent following them; the paid ship-frozen-scope-convergence case covers the review-army half.
Tests ran: local pregate (unit + e2e tiers) at 6f4bbff9: 7 checks; remote gate (Ubicloud) 21,817 tests, 0 failed; Free Tests dispatch run 40420998019 29 jobs green; Windows Free Tests dispatch run 40421001513 (see Test plan).

Pre-Landing Review

Eight passes under the frozen finding scope. Pass 1 (whole diff, 8 specialists + Red Team + QA): 12 INFORMATIONAL findings, none at the blocking floor, all fixed in d39ea5d. Pass 2 (range): 9 noted, clean. Pass 3 (the Step 11 queue): one blocking defect, the co-author trailers appended as a separate paragraph so git interpret-trailers --parse saw only the last one, fixed in 12d0463. Pass 4: two blocking (a spawnSync without timeout in the new trailer test; DOCS_CAPS_KEY_VERSION naming a release main had stamped for another PR) fixed in 48ab55a. Pass 5: one blocking (the new heading test read origin/main, absent in depth-1 CI clones; reproduced) left at the fix-cycle cap and granted by the owner as one bounded pass; pass 6 fixed it in 47e693b (strictly newer than every visible heading; depth-1 clone 15 pass) and read clean. Passes 7 and 8 (docs-only ranges after Steps 13 and 14.5): two wording overclaims corrected in 775d980; pass 8 clean, two notes. Passes 9–11 covered the owner-granted docsync fixture repair after the focused paid run: pass 9 (range 775d980..2524ec4; testing, maintainability, Red Team, Step 11 native and outside) found six floor-level fixture gaps (the record write refused under read-only, the shared housekeeping paths not admitted for the fault and store callers, the fixture install without lib/, the ~ form of the cap gate, the Write tool's temp sibling of the record), fixed in 8aa3578, 2549a32, 0230fc2 and 57ac5b0; pass 10 (range 2524ec4..0230fc2) reproduced the temp-sibling gap with the pinned Claude Code binary against the real observer, the same red the 0230fc2 paid rerun hit, fixed in 57ac5b0; pass 11 (range 0230fc2..57ac5b0) read clean: every watch-installation point of the landing enumerated against the live kernel, every abuse probe refused, five notes. Pass 12 (delta pass on the base merge e78f9be; testing, Red Team, Step 11 native and outside) read clean: the four resolutions reproduce mergeChangelogs and renderDoctorComponentsSh byte for byte and carry every line from both sides, git merge-tree conflicts in exactly those four files, the branch's diff over main equals its diff over the old base; three notes.
REVIEW_LOOP: passes=12 blocking_found=10 deferred=0 noted=43 fixed=30 scope=frozen
Gate edits: none detected (34 listed, 18 read; the 18 untagged hunks are tests and regenerated goldens that follow product changes; the ship parity re-pin 1.7150 → 1.7400 is the declared cap raise above). Later passes added tests only (the carry refusal test, the heading test, the tripwire-compliant trailer test).
Outside review: Codex CLI absent on the host; the outside voice was a subagent on a different model family (openai/gpt-6.1-sol), logged as adversarial-review rows with source outside-subagent: at 9ea5bfd 2 P2 (the trailer-block defect, verified and fixed; the prose checker accepting swapped lane counts, noted), Verdict pass; at 47e693b 1 P2 (noted), Verdict pass; at 775d980 twice NO_FINDINGS, Verdict pass; at 2524ec4 2 P0 (both confirmed by helper replays and fixed in 8aa3578), Verdict fail; at 0230fc2 the reviewer ran on the author's model family, so that row is native coverage; at 57ac5b0 NO_FINDINGS, Verdict pass; at e78f9be NO_FINDINGS, Verdict pass. Native adversarial re-reads at 9ea5bfd (10 informational), 47e693b (6), 5ceaa5e (2 wording, corrected), 775d980 (2 informational, noted), 2524ec4 (4 floor-level, fixed), 0230fc2 (1 floor-level, fixed in 57ac5b0) 57ac5b0 (2 informational, Recommendation ship) and e78f9be (2 informational, Recommendation ship with notes); Step 11.5 bound the pass-12 review, native and outside rows on reviewed tree 740dcf0ca5ab48ce87c0ffacf5fde86c14a75a1d at e78f9be (pass 11 bound on 0e47daf4 at 57ac5b0; passes 9 and 10 bound changed, their fix commits landing under the reviewers).

Review notes

Below the blocking floor (advisory, informational, test-gap or wording items); recorded here and not fixed in this PR.

  • INFORMATIONAL bin/gstack-ship-receipt:554 docs-caps --base fails open: loadPolicyFromBase merges defaults when the base policy has any validation error, cmdDocsCaps surfaces only docs.* errors, so an unrelated invalid key zeroes the declared caps and prints DOCS_CAP: none declared exit 0 (red-team probe confirmed)
  • INFORMATIONAL bin/gstack-ship-receipt:126 receiptVersion decides absent-vs-refusal by regex on versionAtRef's error prose, and a declared .gstack/version-path whose file is missing reads as absent and records version none
  • INFORMATIONAL scripts/resolvers/outside-voice-steps.ts:134 the Step 11 native adversarial prompt still says DIFF_BASE=$RANGE_BASE applies from pass 2 on; the subagent never has RANGE_BASE
  • INFORMATIONAL lib/ship-policy.ts:166 DOCS_CAPS_KEY_VERSION hard-codes 1.91.257.0 but the train assigns the version at merge; nothing ties the constants to the stamped CHANGELOG
  • INFORMATIONAL bin/gstack-coauthor-trailers:51 the range half of the dash guard is unreachable: a positional starting with - is an unknown flag before the guard runs (QA probe)
  • INFORMATIONAL test/gstack-ship-receipt-docs.test.ts:93 untested cell updated × no exception after receiptDocs was removed
  • INFORMATIONAL lib/ship-receipt-prose.ts:54 leaf-only matching accepts swapped, explicitly lane-qualified counts (gate.unit.pass=7; gate.e2e.pass=41 against unit 41 / e2e 7)
  • INFORMATIONAL bin/gstack-ship-receipt:561 docs-caps measures the working tree with fs.statSync, which follows symlinks: a symlink to a tiny file, or an uncommitted trim, passes a cap the pushed head violates; the receipt records no DOCS_CAP result
  • INFORMATIONAL lib/ship-receipt-prose.ts:2 read --check-prose has no caller in ship/SKILL.md or ship/sections/*, though the header, docs/review-policy.md:177 and docs/ship-policy.md say Step 19 / Data PRs run it; RECEIPT_PROSE_MISMATCH exists only when typed by hand
  • INFORMATIONAL lib/ship-receipt-prose.ts:50 once wired, every lane contributes pass/fail/skip leaves, so ordinary prose like '3 fail before the fix' or quoted CI text trips the check; read --check-prose --json also changes read --json's shape
  • INFORMATIONAL lib/headless-artifacts.ts:207 docs is not in the receipt schema, so read/result/queue accept any docs shape; a hand-edited body with docs.status blocked and no exception reads as a valid receipt
  • INFORMATIONAL bin/gstack-ship-receipt:548 docs-caps --policy with non-object JSON exits 0 'none declared': the root validation error (path '') is dropped by the docs-prefix filter; the POLICY_INVALID line names .gstack/ship-policy.json instead of the given file
  • INFORMATIONAL bin/gstack-coauthor-trailers:80 --message writes trailers after everything, so on a git commit -v COMMIT_EDITMSG they land below the scissors line and are discarded while COAUTHORS: n appended is printed; --message --json consumes --json as the file name
  • INFORMATIONAL lib/ship-policy.ts:165 REVIEW_SCOPE_KEY_VERSION 1.91.249.0 → 1.91.256.0 rejects policies written under released 1.91.256.0 with a minimum in 1.91.249.0–1.91.255.0; CHANGELOG:37 still says since 1.91.249.0
  • INFORMATIONAL ship/sections/documentation.md.tmpl:105 docs-audit.json is an unsigned self-report half-protected against staleness: a step range re-entering at 17–21 reuses whatever is on disk, and a run ending Step 14.5 blocked writes nothing so write --docs @… fails with a bare ENOENT exit 2
  • INFORMATIONAL bin/gstack-ship-receipt:460 asId maps a per-path or test patch-id git failure to '' (no diff), so a one-sided failure can omit the changed path from the refusal's names or flip the tests-changed evidence; the top-level product check is guarded
  • INFORMATIONAL ship/sections/adversarial.md.tmpl:97 the Step 11 prompt says DIFF_BASE=$RANGE_BASE applies from Step 9's pass 2 on, but Step 11 first runs after Step 9 converges and has read nothing yet, so a literal reading reviews only the last range and skips the branch; this run read the whole branch against the merge base
  • INFORMATIONAL bin/gstack-coauthor-trailers:86 token-specific trailer.co-authored-by.key/.cmd/.command config still rewrites the new lines (key=Reviewed-by turns co-authors into Reviewed-by while --json reports Co-authored-by); only the user's own git config reaches it
  • INFORMATIONAL bin/gstack-coauthor-trailers:87 when --in-place cannot create its temp file git exits 128 with empty stderr, so the error line ends in 'cannot append to : ' with no detail
  • INFORMATIONAL bin/gstack-coauthor-trailers:85 a missing message file now gets a leading blank line (commit cleanup strips it); a symlinked message path is replaced by a regular file (--in-place renames over it)
  • INFORMATIONAL bin/gstack-coauthor-trailers:16 --no-divider needs git >= 2.20; older git exits 1 'unknown option' where the hand-rolled append worked, and the exit legend says exit 1 is only an unresolved range
  • INFORMATIONAL test/gstack-coauthor-trailers.test.ts:77 the two direct git interpret-trailers --parse assertions omit env: ENV, so a developer's global trailer.* or core.commentChar reaches them while the bin under test runs isolated
  • INFORMATIONAL lib/ship-policy.ts:168 the heading guard is one-shot: once any heading >= the constant exists the key is skipped forever, so DOCS_CAPS_KEY_VERSION is right only if this PR stamps as 1.91.258.0 (the slot call carries the move); archiving old CHANGELOG headings would make released keys fail the test
  • INFORMATIONAL bin/gstack-coauthor-trailers:86 the pinned interpret-trailers placement (--no-divider, --where end, --if-exists addIfDifferentNeighbor, trailer.separators=:) has no dedicated test; QA pass 6 probed a --- body line and a hostile trailer.* config by hand
  • INFORMATIONAL test/gstack-ship-policy.test.ts:83 git show origin/main:CHANGELOG.md (1.9 MB) exceeds spawnSync's default 1 MiB maxBuffer (ENOBUFS), so the base-branch headings never load and the heading check reads the working tree only; maxBuffer: 64 MiB fixes it
  • INFORMATIONAL docs/unattended.md:194 the ".meta.json" half of the unavailable-cause sentence holds only when a runner was selected and then failed; the no-runner refusal (OUTSIDE_RUNNER_UNAVAILABLE, bin/gstack-outside-voice:103-106) writes the stderr line alone and no meta.json (pass 8, Red Team and native re-read)
  • INFORMATIONAL test/helpers/docsync-observer.ts:233 the Step 14.5 housekeeping commands are exact-match only: a decorated form (2>&1, ; echo $?, a $HOME spelling, an && join, --base origin/main) is refused as outside the interface, which the interface text states; actor behaviour under test, not a helper defect
  • INFORMATIONAL test/helpers/docsync-observer.ts:253 gstack-ship-receipt --help is refused while the interface grants --help for the other three binaries; the next most likely actor refusal
  • INFORMATIONAL test/helpers/docsync-observer.ts:160 admitting the record paths for every caller removes the kernel-level catch of a record written on a blocked fault outcome or in store; nothing in the fixture consumes the record and production is defended by gstack-ship-receipt write --docs refusing a blocked record without an exception; fix would assert the record absent in the blocked fault scenarios
  • INFORMATIONAL test/helpers/docsync-observer.ts:31 within one 10 ms poll window a symlink renamed onto the record and unlinked before a legitimate landing is admitted; the same sequence works with no sibling at all (pre-existing class), and the actor cannot create symlinks through Write/Edit or the gated Bash grammar; requiring modify+close_write would refuse the MOVED_FROM-only shape the kernel delivers when the watch lands between close and rename
  • INFORMATIONAL test/helpers/qa-functional-observer.ts:213 events inside a directory created during the run are seen only when a drain tick lands before the activity ends, so a first write into a fresh directory is judged by chance; pre-existing, benign for the record once its sibling is admitted
  • INFORMATIONAL test/docsync-command-grammar.test.ts:551 the two partial landing shapes the kernel delivers (close_write+moved_from only; moved_from alone) are not pinned; landing.slice(1) keeps modify
  • INFORMATIONAL test/docsync-command-grammar.test.ts:530 expect(gate.stderr).toBe('') is strict: a future Bun or lib warning reddens the free test rather than the paid case
  • INFORMATIONAL test/helpers/docsync-interface.ts:12 docsCapsCommand pins one literal path form; actor spelling drift is a flake risk, not a defect
  • INFORMATIONAL test/gstack-ship-policy.test.ts:90 after the base merge, main's 1.91.258.0 heading makes the newer-than-every-heading guard skip the docs key, so a stale DOCS_CAPS_KEY_VERSION is caught by no test; neither restamp nor release-cut references the constant, so the stamp's move (the recorded slot note) is a hand step
  • INFORMATIONAL test/helpers/carve-guards.ts:171 ship parity measures 326,604 / 187,706 = 1.73998 against the 1.7400 cap (4 bytes of headroom) and the comment's measured line is stale; pre-existing on the branch, owned by the slot re-measure
  • INFORMATIONAL docs/troubleshooting.md:4684 the additive merge resolution dropped the blank line between the DOCS_AUDIT_BLOCKED Fix paragraph and main's <a id="gstack-pr-wait"> anchor; the id still lands and the heading still breaks the paragraph (two identical pre-existing spots on main)
  • INFORMATIONAL ship/sections/review-army.md:379 pre-existing: the item-4 (FIXTURE_SUMMARY_MODE) replacement text for the Security specialist uses git diff "$DIFF_BASE" without the DIFF_BASE= assignment, so a literal substitution hands that one specialist an unset variable (pass 8 native re-read; outside this PR's range)

Exploratory QA

CLI surfaces only (gstack-ship-receipt write --docs / docs-caps / read --check-prose / version none / carry, gstack-coauthor-trailers, gstack-review-scope defer / summary): pass 1 14 charters, one probe not run (late-defer summary, rerun at pass 2: 14 of 14 pass); passes 4, 5 and 6 probed the trailer placement by hand (--- body lines, hostile trailer.* config, scissors, leading blank) with git interpret-trailers --parse on each result: NO FINDINGS. Passes 3, 7 and 8 reused the unchanged candidate or were prose-only. No browser or API surface.

Design Review

No frontend files changed — design review skipped.

Eval Results

Paid ship-frozen-scope-convergence (behavior, gate tier, panel of 3): at f9e8f7b PASS 2/3 (✗✓✓; trial 1 a fixture-message assertion in test/helpers/ship-frozen-scope-actor.ts, repaired in d39ea5d), $0.70; PASS 3/3 at 775d980, $0.65. The 51 /ship and /review own cases focused at 775d980 in the CI image on Ubicloud: 49/51, $22.35; ship-docsync-completion and ship-docsync-current red in round 1 and on their one rule-16 rerun, both on the same fixture-interface gap (the actor stopped Documentation: blocked at the undeclared Step 14.5 cap gate), which is a fixture defect rather than a product one and was repaired under the owner's bounded grant (see "Docsync fixture" above). The two cases were then rerun alone: at 2524ec4 red twice (Cannot find module '../lib/headless-artifacts' from the fixture install; the ~ cap-gate form outside the interface), $3.94; at 0230fc2 red twice on forbidden docs write: .gstack/tmp/docs-audit.json.tmp.<pid>.<12 hex> (the Write tool's atomic landing of the record), $1.81; at 57ac5b0 PASS 2/2 in round 1, $2.09. No threshold, budget or case kind changed; every attempt is recorded above.

Plan Completion

Plan completion audit: not run (no plan is bound to this branch and no docs/designs/ file matches). Fix: add "Plan: " to the PR body, or run /autoplan.

Issues

Refs #3504

Verification Results

No Step 8.1 obligations (no bound plan). Docs caps: gstack-ship-receipt docs-caps --base main → DOCS_CAP: none declared, exit 0. TODO scan clean.

TODOS

No TODO items completed in this PR.

Documentation

Status: current — read-only audit (ship3487-20261026T232704Z-r3); no edits, no blockers. Scope: the capy/version-less-repos-docs candidate against base 576839c (10 commits, head 775d980, clean tree; every candidate hash matches the working tree and the post snapshot reports head_changed=false, content_changed=[], newly_dirty=[]): docs/ship-policy.md, docs/review-policy.md, docs/unattended.md, docs/troubleshooting.md, CHANGELOG.md [Unreleased], review/checklist.md, ship/SKILL.md.tmpl and ship/sections/{changelog,documentation,pr-body,review-army}.md.tmpl with their generated output, cross-checked against bin/gstack-ship-receipt, bin/gstack-coauthor-trailers, bin/gstack-outside-voice, lib/ship-receipt{,-docs,-prose}.ts, lib/ship-policy.ts, lib/review-scope.ts, lib/outside-voice-runner.ts, scripts/resolvers/review-army.ts and ship/sections/adversarial.md. Attempt 2's two blockers and the two reviewer wording items are corrected in commits 5ceaa5e and 775d980 and verified against the code: (1) docs/unattended.md:184-203 no longer names "none" or unavailable_reason, says codex for completed CLI output and source: "in-host" for the native row (ship/sections/adversarial.md:273), and locates the unavailable cause on the gstack-outside-voice run: stderr line and in <out>.meta.json (bin/gstack-outside-voice:115,122; the no-runner path writes its cause as the OUTSIDE_RUNNER_UNAVAILABLE line at :104); (2) CHANGELOG.md:16 now reads "the paths the branch itself touched and names at most CARRY_NAMED_PATHS (20)" (lib/ship-receipt.ts:149, bin/gstack-ship-receipt:463-470); (3) CHANGELOG.md:19 and docs/review-policy.md:174 scope the literal DIFF_BASE=<diff-base> claim to the specialist and Red Team prompts scripts/resolvers/review-army.ts renders for /ship (review-army.ts:98,142,321; ship/sections/review-army.md:19,385,556), leaving adversarial.md:97's $RANGE_BASE outside the claim. The other claims new since attempt 2 also hold: docs-caps [--base <ref>] [--policy <file>] reading origin/'s policy with POLICY_SOURCE_UNAVAILABLE on an unreadable base (bin/gstack-ship-receipt:553-555), documentation.md.tmpl:11 rm -f .gstack/tmp/docs-audit.json on first entry and :87 docs-caps --base <base>, coauthor-trailers' leading-- usage refusal (:52), origin/ resolution (:59-60) and git interpret-trailers --where end (:86), LATE_DEFER_SKILL = 'review-late-defer' (lib/review-scope.ts:261), REVIEW_SCOPE_KEY_VERSION 1.91.256.0 / DOCS_CAPS_KEY_VERSION 1.91.258.0 with the unreleased-key heading test (test/gstack-ship-policy.test.ts:78-91), receiptVersion returning "none" only past VERSION, package.json#version, stamp files and CHANGELOG (bin/gstack-ship-receipt:123-134) and the shared-leaf / 3 pass-through prose rule (lib/ship-receipt-prose.ts:30-56). Checks: bun run gen:skill-docs --dry-run 138 FRESH, nothing stale; gstack-banned-terms check --diff-base 576839cb: none; focused tests 325/325 (ship-workflow-clarity, gstack-ship-receipt-docs, gstack-ship-policy, review-scope-followups, gstack-coauthor-trailers, ship-receipt-prose, troubleshooting-anchors); git status clean before and after; no repository writes.

Documentation health:
README.md Current (no claim touched by the diff)
ARCHITECTURE.md Current (no entity from the diff; no diagram drift)
CONTRIBUTING.md Current
CLAUDE.md / AGENTS.md Current (/ship row stays generic)
CHANGELOG.md Current ([Unreleased] entry matches the code; wording items from attempts 1-2 corrected)
TODOS.md Current
docs/ship-policy.md Current (docs row, #ship-receipt, #receipt-carry match lib/ship-policy.ts, receiptVersion, lib/ship-receipt-prose.ts, CARRY_NAMED_PATHS 20, git 2.39 probe)
docs/review-policy.md Current (fan-out, checklist ids, #porting-a-contributors-work, late-defer row, literal diff base scoped to review-army.ts prompts)
docs/unattended.md Current (#ship-evidence row fields match ship/sections/adversarial.md:255-273 and bin/gstack-outside-voice)
docs/troubleshooting.md Current (3 new anchors match lib/result-codes-release.ts; #outside-runner-unavailable at :2879)
review/checklist.md Current
ship/*.tmpl Current (generated SKILL.md and sections fresh)

Decisions (not doc edits): docs/unattended.md:187 "the outside provider that reviewed" names no value for the host-subagent row; gstack-outside-voice run reports provider=host-subagent and adversarial.md:271 only says SOURCE is "the actual outside provider or native in-host source", so the prose is consistent but leaves the literal to the host. ship/sections/adversarial.md:97 (generated, unchanged by this branch) still shows DIFF_BASE=$RANGE_BASE for the Step 11 prompt; the docs now scope the literal-sha claim to review-army.ts prompts, so no contradiction remains, noted for the section owner. DOCS_CAPS_KEY_VERSION is 1.91.258.0 (lib/ship-policy.ts:168) and CHANGELOG.md:7 and :23 say "the release that stamps this entry": true only if this entry stamps as 1.91.258.0 (branch VERSION 1.91.256.0, main at 1.91.257.0). CHANGELOG.md:10 "First panel 3/3 at $0.66" is a run result outside the tree, unverified here. lib/ship-receipt-prose.ts:2 still says the prose check runs at "/ship Step 19" while no ship section invokes --check-prose (code comment, unchanged from attempts 1-2).

Documentation coverage:
version-less repo (Step 12 skip, receipt "none") reference ✅ ship-policy#ship-receipt how-to ✅ ship/sections/changelog.md tutorial ❌ explanation ✅
write --docs / receipt docs record ✅ ship-policy ✅ documentation.md, pr-body.md ❌ ✅ troubleshooting#docs-audit-blocked
docs-caps --base, policy docs.caps ✅ ship-policy table ✅ documentation.md ❌ ✅
read --check-prose ✅ ship-policy ❌ (no step runs it; "Data PRs run it before READY" only) ❌ ✅ troubleshooting
DOCS_AUDIT_BLOCKED / RECEIPT_GIT_TOO_OLD / RECEIPT_PROSE_MISMATCH ✅ troubleshooting anchors n/a n/a ✅
bin/gstack-coauthor-trailers ✅ review-policy ✅ synopsis ❌ ✅
--review-fanout ✅ review-policy#reviewer-fan-out ✅ ship/sections/review-army.md ❌ ✅
carry git >= 2.39, CARRY_NAMED_PATHS walk ✅ ship-policy#receipt-carry ✅ unattended#ship-evidence ❌ ✅
review-late-defer row, literal DIFF_BASE, cap before edit, .gstack/tmp scratch ✅ review-policy, ship-policy ✅ review-army.md ❌ ✅
defer 200-issue truncation (DEFERRED_SEARCH) CHANGELOG only ❌ ❌ ❌
REVIEW_SCOPE_KEY_VERSION 1.91.256.0 / DOCS_CAPS_KEY_VERSION ✅ CHANGELOG n/a n/a ✅ CHANGELOG
paid case ship-frozen-scope-convergence CHANGELOG only ❌ ❌ ❌
cross-family outside voice (unattended#ship-evidence) ✅ ✅ ❌ ✅
Common gaps: read --check-prose and DEFERRED_SEARCH: truncated have reference-only coverage; ship-frozen-scope-convergence is CHANGELOG-only. Coverage gaps are reported, not filled.

Diagram drift: none (ARCHITECTURE.md carries no entity from this diff).

Test plan

🤖 Generated with Claude Code

@capy-ai
capy-ai Bot changed the base branch from harness-lane-e/ship-review-convergence to main October 26, 2026 20:48
@trunk-io

trunk-io Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

…n-scope paid case, and the review-loop follow-ups

Follow-up to the review-loop convergence PR: Step 12 and the CHANGELOG step skip cleanly in a repository with no version source (receipt version "none"); the receipt records the docs audit outcome and the owner exception (DOCS_AUDIT_BLOCKED without one) and a policy may declare doc caps (gstack-ship-receipt docs-caps); docs/unattended.md names the READY evidence and the cross-family outside voice; the ship-frozen-scope-convergence behaviour case runs the generated Step 9.4 under review_scope frozen through the real binaries; carry probes git >= 2.39 (RECEIPT_GIT_TOO_OLD); defer passes the repository to gh repo view positionally and names its search limit; late defers count without being passes; reviewers diff from RANGE_BASE on pass 2+; the cap check runs before edits; --review-fanout batches specialists by free slots; read --check-prose compares quoted counters with the receipt (RECEIPT_PROSE_MISMATCH); checklist rule ids prereg-with-results and test-keyboard-count-loop; gstack-coauthor-trailers.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@garrytan
garrytan force-pushed the capy/version-less-repos-docs branch from 66efb94 to 2d73fad Compare October 26, 2026 20:50
Seven test files, no product change. The pull_request run at 2d73fad
failed 5 Linux shards and 4 Windows shards:

- test/ship-frozen-scope-actor.test.ts imported only test code, so the
  test-of-test ratchet refused it; the first case now recomputes the loop
  summary with summarizeReviewLoop/reviewLoopLine from lib/review-scope and
  asserts the exact REVIEW_LOOP line. Its three cases replay the bash
  workflow through bash -c and the shebang bins, so they are POSIX-only.
- test/codex-host.test.ts: the new gate case is Claude-specific (33 -> 34).
- test/paid-retry-supervision.test.ts: the gate census fixture now carries a
  trial record for the one planned behavior-kind gate case, the way
  test/ci-paid-coordination.test.ts already does.
- test/review-fix-range.test.ts asserted the pre-#3487 DIFF_BASE sentence;
  it now asserts the ${RANGE_BASE:-merge-base} clause that carries the same
  contract (every reviewer reads the range from pass 2 on).
- test/gstack-coauthor-trailers.test.ts: the fixture sets its own git
  identity; a CI runner has none to auto-detect ("Committer identity
  unknown").
- test/review-scope-followups.test.ts and test/gstack-ship-receipt-docs.test.ts:
  the gh and old-git stand-ins are sh scripts on a colon-joined PATH, which
  CreateProcess cannot run, so those three cases skip on win32.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
garrytan and others added 8 commits October 26, 2026 21:46
Twelve informational findings from the /ship pass-1 review, all below the
blocking floor, fixed in place:

- docs-caps reads docs.caps from origin/<base>'s policy (--base <ref>), never
  the branch's copy; an unavailable base policy refuses with
  POLICY_SOURCE_UNAVAILABLE instead of substituting DEFAULT_POLICY
- receiptVersion returns "none" only when the stamp file is absent; other
  errors surface as undefined
- checkReceiptProse groups counters by leaf key and uses word boundaries that
  cover hyphenated names, so shared leaf keys and hyphenated words no longer
  report RECEIPT_PROSE_MISMATCH
- gstack-coauthor-trailers refuses a --range/--base starting with "-",
  prefixes origin/ when origin/<ref> resolves (slash-named branches), and
  passes --end-of-options to git log
- REVIEW_SCOPE_KEY_VERSION and DOCS_CAPS_KEY_VERSION name the releases that
  first read their keys
- the Step 11 late-defer row logs under skill review-late-defer so a tokenless
  review row never reads UNVERIFIED; summarizeReviewLoop counts both
- the "already filed" literal is one constant shared by bin and renderer
- receiptDocs (dead) removed
- Step 14.5 clears .gstack/tmp/docs-audit.json on first entry
- dispatched review prompts carry a literal diff-base sha (<diff-base>) instead
  of a shell variable the reviewer process never sees
- the coauthor-trailers tests launch the bin through runScriptSync so the
  Windows lane can run them

Tests extended for each change; SKILL.md, sections and goldens regenerated.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
gstack-coauthor-trailers --message appended the new Co-authored-by lines as a
separate paragraph after existing trailers, so git interpret-trailers (and
GitHub attribution) read only the last paragraph and the existing co-author
lost credit. The new lines now join the existing trailer block; the test
checks the result with git interpret-trailers --parse.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
gstack-coauthor-trailers --message now runs git interpret-trailers --in-place,
so the appended lines join the existing trailer block whatever its shape
(CRLF, comment lines, folded continuations) and the existing co-author keeps
attribution; the interpret-trailers check in the test carries a timeout for
the spawnSync tripwire. DOCS_CAPS_KEY_VERSION names the release after the
newest CHANGELOG heading on main (1.91.258.0), and a test ties every
unreleased policy key to that next release so a stamp elsewhere fails loudly.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…trailer placement

The CHANGELOG-heading test asked for the exact next release after the newest
heading, which a depth-1 CI clone (no origin/main) computes from the branch
alone, so it went red there. It now requires an unreleased key's version to be
newer than every heading the checkout can see, which holds at depth 1, on the
stamped train tree and on main; the ship-policy comment says who moves the
constant when the stamp lands under another number.

gstack-coauthor-trailers pins git interpret-trailers' placement on the command
line (--no-divider so a --- body line is not a divider, --where end,
--if-exists addIfDifferentNeighbor, trailer.separators=:, -- before the path)
so a user's trailer.* config cannot replace or drop the existing co-author.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
CHANGELOG [Unreleased]: docs-caps --base <base> reading origin/<base>'s
policy, the review-late-defer row, the literal <diff-base> prompt rule, the
coauthor-trailers placement and refusals, the policy key versions (review_scope
1.91.256.0 re-pin, docs.caps at the stamping release), the version-less
conditions split between Step 12 and the receipt, and the carry refusal wording.
docs/ship-policy.md, docs/review-policy.md and docs/unattended.md follow the
code: docs-caps --base, the literal diff-base sha, the trailer block, the
gstack-outside-voice run binding and the Step 11 row fields.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…ame where the outside-voice cause lives

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
garrytan and others added 7 commits October 27, 2026 00:40
…xclude .gstack/tmp at the Entry

The ship-docsync-completion and ship-docsync-current paid cases failed twice at
775d980: Step 14.5's continue path now runs gstack-ship-receipt docs-caps and
writes .gstack/tmp/docs-audit.json, and the docsync fixture's closed interface
declared neither, while its repository had no origin/main for docs-caps to read.
The actor stopped correctly (blocked, no exception) and never reached the
publication stand-in.

- test/helpers/docsync-interface.ts: the three housekeeping commands (the shared
  exclude line, rm -f of the record, docs-caps --base main) and the record write
  are declared, byte for byte with the generated section; DOCS_AUDIT_RECORD_PATHS
  names what the kernel observer may see.
- test/helpers/docsync-observer.ts: accepts exactly those commands and the record
  write; every neighbour (another base, --json, write --docs, another .gstack file)
  stays outside the interface.
- test/helpers/docsync-fixture.ts: every scenario pushes main to the fixture
  remote, as Steps 0-14 would have.
- ship/sections/documentation.md.tmpl: the Entry runs the shared .gstack/tmp
  exclude line before rm -f, so the record never surfaces as an untracked file
  when no earlier step added it; the caps paragraph tightened to hold the ship
  parity ratio at 1.7400.
- test/docsync-command-grammar.test.ts: pins the literals against the generated
  section and the refusals around them.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… and the fault cases too

Pass 9's outside voice found two gaps in the fixture change (2524ec4): a
read-only audit (ship-docsync-current) must still write .gstack/tmp/docs-audit.json,
but docsToolFailures flagged every product write under readOnly before the
record allowance; and the unseeded fault cases (missing-asset, legacy-completion)
run the Entry too, so their kernel-write check saw .git/info/exclude as a
forbidden write because only the lifecycle test named the housekeeping paths.

- docsToolFailures: the record write is permitted under readOnly; the document
  and every other product file stay refused.
- docsWriteFailures: DOCS_AUDIT_RECORD_PATHS are permitted for every caller, so
  the fault evaluator needs no per-scenario list; anything else under .git or
  .gstack stays forbidden.
- test/docsync-command-grammar.test.ts pins both: the record under readOnly, the
  document refused there, the observed housekeeping paths accepted with an empty
  allowance and two neighbours refused.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… section prints (pass 9 Red Team note)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…tainability note)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… cap gate can load (2524ec4 rerun: module error, not a verdict)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…rd (0230fc2 rerun: both lifecycle cases red on it)

The paid rerun at 0230fc2 cleared every earlier refusal and both cases then
failed on one path: forbidden docs write: .gstack/tmp/docs-audit.json.tmp.<pid>.<12 hex>.
Claude Code's Write and Edit tools land every file, new ones included, through
that sibling plus fsync and rename, and the fixture's kernel observer proved
such a landing for the document only (atomicTargets: [DOC_PATH]).

The observer now treats the record's sibling as a transient file too, and
docsWriteFailures admits it only as the cookie-paired MOVED_FROM source of a
MOVED_TO on the record whose other events are create/modify/attrib/close_write
and which is left in neither snapshot nor in changed. A lingering sibling, an
unpaired move, a move onto another path or a sibling of the document moved onto
the record stay forbidden (grammar test). A live check on this machine saw the
second landing's create/modify/close_write/moved_from events admitted and a
stray sibling refused.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…docs

CHANGELOG.md through mergeChangelogs (the [Unreleased] entry kept above main's
headings); bin/gstack-doctor-components.sh regenerated from
scripts/gen-doctor-components.ts; docs/troubleshooting.md and
lib/result-codes-release.ts additive (gstack-pr-wait's two codes beside this
branch's three). DOCS_CAPS_KEY_VERSION unchanged; the stamp moves it.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@github-actions github-actions Bot changed the title feat(ship): version-less repos, docs-audit record and caps, the frozen-scope paid case, and the review-loop follow-ups v1.91.270.0 feat(ship): version-less repos, docs-audit record and caps, the frozen-scope paid case, and the review-loop follow-ups Oct 27, 2026
@garrytan
garrytan force-pushed the capy/version-less-repos-docs branch from c2a11ce to e78f9be Compare October 27, 2026 07:13
FILES: CHANGELOG.md VERSION agents-digest/gstack-AGENTS.md package.json
MERGE_CONDITION: sha=e78f9beb5b4be0ac80be18f656f754d4a6af0e64
NEW_VERSION=1.91.270.0
base=295b32e2c47a3c30a2b797739fd0300012533f55 expect-order=3487

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai
capy-ai Bot merged commit f27a760 into main Oct 27, 2026
70 of 72 checks passed
garrytan added a commit that referenced this pull request Oct 27, 2026
GSTA-36 grant 2026-10-27. On the tree merged with f27a760 the ship union is 326,691 / 187,706 = 1.7404 against #3487's 1.7400; the only ship bytes this PR adds are the handoff section's one-line pointer. Cap 1.7400 -> 1.7405, measurement appended to the comment.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
capy-ai Bot added a commit that referenced this pull request Oct 27, 2026
…y versions move through stamp_paths at the slot stamp (#3511)

* fix(ship-policy): DOCS_CAPS_KEY_VERSION is 1.91.270.0; key versions move through stamp_paths at the slot stamp

#3487 was written naming 1.91.258.0 for docs.caps and main stamped that
number for another PR first; the slot call cannot edit anything beyond the
four stamp files, so the constant shipped stale. lib/ship-policy.ts now sits
in .gstack/ship-policy.json stamp_paths with the _KEY_VERSION = '{version}'
template, so a new key written as a tentative future version is moved by
gstack-restamp's stamp_paths stage at the slot (read from the base policy,
so live from the next PR on). test/gstack-ship-policy.test.ts gains the
check the incident lacked: a released key's version must be a heading whose
entry names the key. Dry-run proof: a tentative 1.91.272.0 on a branch line
moved to the allocated 1.91.271.0 with --policy-from head.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(ship-policy): tentative key versions are clear of main's pace; the receipt accepts the move only at the base version until #3512

Pass-1 review notes: the next patch above the fork point is the number main
takes first, so the convention names the next minor; and the tree receipt's
stamp-only check (lib/tree-receipt.ts stampOnlyHunks, with stampOnlyText and
stampFreeTree) rewrites only base VERSION -> new VERSION, so a tentative move
passes the train only when the tentative value equals the base version at the
slot. Filed as #3512 (outside this diff, deferred under the frozen scope).

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(ship-policy): read origin/main's CHANGELOG with a 64 MiB maxBuffer; say plainly that a new-key PR cannot clear the train until #3512

Pass-2 Red Team: CHANGELOG.md is past spawnSync's default 1 MiB maxBuffer,
so both CHANGELOG-reading tests dropped origin/main's file silently and the
incident shape passed at the pin. With the buffer the released-key test sees
main's headings on a full clone. The comment and CHANGELOG now state the
practical consequence of the receipt limit.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(ship-policy): gstack's own policy excerpt names lib/ship-policy.ts under stamp_paths

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
capy-ai Bot added a commit that referenced this pull request Oct 27, 2026
…fault prompts, gstack-post --attribute, the unattended grant and a CONTRIBUTING porting section (#3497)

* feat(absorb-tstack): /modernize skill, per-skill Codex default prompts, gstack-post --attribute, the unattended grant and a CONTRIBUTING porting section

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(modernize): read the PR text through gstack-issue-guard; re-measure the context ceiling

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: pre-landing review fixes

- gstack-post: with --attribute, report scan findings at the body file's own
  line numbers and a finding inside the callout as PART: attribute (the
  coordinates were shifted by the three callout lines)
- /modernize: route commit messages through gstack-issue-guard with the rest
  of the PR text, read isCrossRepository and maintainerCanModify, fetch a fork
  head from pull/N/head, refuse a PR whose head is the base branch, and list
  moved files NUL-safely
- docs/unattended.md: say that /ship never rebases or force-pushes and an
  unattended /modernize stops at its verdict
- CHANGELOG: seven skills carry a codex_default_prompt, not six

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: /modernize fetches a fork head with a forced refspec and stops when the PR moved

A rerun after the author force-pushed left refs/modernize/pr-N stale (the
non-forced refspec is rejected with exit 0 through the pipe), and the lease
pinned to the current remote head would then have let the rebased stale head
overwrite the author's newer commits. The fetch is forced, Steps 2 and 4 stop
when the head is not the one observed in Step 1, and the head-is-base guard
applies only to same-repository PRs (a fork's main into main is a valid head).

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: /modernize stops on merge commits in the PR range and pushes a fork head to the fork

A plain git rebase drops merge commits and git range-diff compares only the
non-merge patches, so a change authored in a PR's merge commit disappeared
while the proof printed = for every patch and Step 5 force-pushed the loss.
Step 4 now counts merges in $MERGE_BASE..$OLD_HEAD and stops when there are
any, switches with -C so a rerun after a refused lease does not fail on the
existing branch, and asks for a cross-repository diff to be read as untrusted
input before the repository's test command runs it. Step 5 pushes a fork head
to the fork's URL with the same pinned lease instead of to origin, where the
lease could never match.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test: cover the Codex default-prompt render, the openai.yaml ownership proof and the unattended grant

Adds the /ship coverage audit's tests: test/host-renders-openai-yaml-proof.test.ts
drives bin/gstack-host-renders.sh's weakened proof against a rendered yaml, a
hand-written one and a generic-prompt one; test/unattended-grant.test.ts pins the
docs/unattended.md grant section and the handoff pointer; test/gen-skill-docs.test.ts
adds modernize to the skills whose codex_default_prompt must reach openai.yaml.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs: name the static lists a new skill still needs and the Codex metadata file

From the ship documentation audit: CONTRIBUTING's new-skill checklist said no
static list needs a row, which this PR disproved (lib/doctor-components.ts
SKILL_REQUIREMENTS and the catalog rows); the host comparison table and
docs/ADDING_A_HOST.md gain the agents/openai.yaml default_prompt source; a blank
line before the new docs/unattended.md grant heading.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: pre-landing review fixes

CHANGELOG [Unreleased] gate-integrity record: the catalog and context-budget
figures re-measured on top of main (1,314 -> 1,359; modernize 9466;
alwaysOnTotal 7458 -> 7880), as the merge commit's ratchets state.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs: name the optional codex_default_prompt key in the new-skill checklist

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(parity): re-pin the ship union cap at 1.7405 after the main merge

GSTA-36 grant 2026-10-27. On the tree merged with f27a760 the ship union is 326,691 / 187,706 = 1.7404 against #3487's 1.7400; the only ship bytes this PR adds are the handoff section's one-line pointer. Cap 1.7400 -> 1.7405, measurement appended to the comment.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(changelog): the [Unreleased] gate-integrity bullet names the ship cap re-pin

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: pre-landing review fixes

CHANGELOG [Unreleased]: end the Codex default-prompts sentence at
"generator input only." so bin/gstack-prose-lint --unreleased --gate
(main's new quality-gate step) passes, and restate the gate-integrity
bullet's figures for the tree merged with 1f246e3: ship cap
1.7524 -> 1.7528 (329,005 / 187,706), modernize 9466 -> 3772 after the
preamble hoist, alwaysOnTotal 7769 -> 7880, catalog 1,359 unchanged.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix: pre-landing review fixes

CHANGELOG [Unreleased] gate-integrity bullet names the current ship cap pin
(1.7525 -> 1.7529, measured 329,024 / 187,706 on the 392f50d merge) and keeps
the 1.7528 pin in the earlier-merges clause.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant