Skip to content

feat(adapter-jig): stamp go ecosystem end-to-end THROUGH the conformance jig (J3) - #1171

Merged
artyhoo merged 16 commits into
stagingfrom
feature/adapter-jig-j3-d4db43
Aug 6, 2026
Merged

feat(adapter-jig): stamp go ecosystem end-to-end THROUGH the conformance jig (J3)#1171
artyhoo merged 16 commits into
stagingfrom
feature/adapter-jig-j3-d4db43

Conversation

@artyhoo

@artyhoo artyhoo commented Jul 25, 2026

Copy link
Copy Markdown
Owner

feat(adapter-jig): stamp go ecosystem end-to-end THROUGH the conformance jig (J3)

Umbrella: adapter-jig · Stage: J3 (first NEW family stamped) · Tier: 1 (executor carries §2.1 design judgment per <!-- bridge-profile: Z.AI GLM-5.2 SDK --> marker; routing override 2026-07-25).
Base: staging (4 commits ahead: 3 feature + 1 merge-forward b4435630).
Honest scope label: the go family is stamped end-to-end THROUGH the 22-arm conformance suite. The runner CI arm link will be filled in below when the PR opens.

§0 5-deliverable / 3-commit map

Deliverable (§2 of kickoff) Commit Surface
(1) adapter + (2) prefix registration + detector Stack widening + resolveCtxForRoot threading dfbdc045 packages/core/research/ecosystem-go.ts:1-182, packages/core/research/ecosystem-name.ts:22, packages/core/detector/types.ts, packages/core/detector/read-python-cargo.ts, packages/core/synthesizer/resolve-ctx.ts
(3) delivery lane setup.d/47-go.sh + install.sh wiring + rules-lock + snapshot baselines 71bb5fe9 setup.d/47-go.sh:1-338, install.sh (3 surgical edits), tests/install-sh/snapshot.sh, tests/install-sh/baselines/go/{greenfield,brownfield-golangci}.fingerprint, tests/install-sh/rules-lock-schema-parity.test.sh
(4) pinned go arm in audit-self.yml + F10 two-surface pin parity via packages/core/templates/go/{.golangci.yml,github-actions-ci.yml} 4b3aa122 .github/workflows/audit-self.yml (+48 LOC go arm), packages/core/templates/go/.golangci.yml, packages/core/templates/go/github-actions-ci.yml
(5) BASELINE + snapshot lockstep — adapter wired in the SAME PR (H1 lockstep: BASELINE = 0 stays 0) all three packages/core/research/ecosystem-unwired-debt.test.ts:106 (BASELINE unchanged), tests/install-sh/baselines/go/*.fingerprint

Atomic: ONE PR, ZERO edits to F1-F11 frozen rows, ZERO skill/IR/core-edits (arm G3).

§1 Frozen-row compliance — ZERO edits to F1-F11

Row Surface Verified by
F1 (3-method adapter seam) packages/core/research/allowlist-resolver.ts:133-137 unchanged — goAdapter implements, never edits
F2 (ResolveCtx; Tier-1 misses for absent adapter) allowlist-resolver.ts:164-171 unchanged
F3 (tier1For host-derivation pipeline) allowlist-resolver.ts:189-243 unchanged — see §3 below for the hard-node resolution
F4 (ecosystem prefix set — extension permitted) packages/core/research/ecosystem-name.ts:22 IN-SCOPE extension: added 'go' to the Set (kickoff §1.1 F4 explicitly authorises)
F5 (typed-const adapter idiom) packages/core/research/ecosystem-go.ts:23 export const goAdapter: EcosystemAdapter = { verbatim
F7 (delivery-cell grammar) setup.d/47-go.sh:73-145 fresh / idempotent / REFUSE-LOUDLY mirror of setup.d/46-cargo.sh
F8 (firing self-check) setup.d/47-go.sh:159-225 mktemp -d plant + paired clean control + loud-degrade + rc=0
F9 (snapshot byte-identity) tests/install-sh/snapshot.sh greenfield + brownfield-golangci baselines captured
F10 (two-surface CI pin parity) .github/workflows/audit-self.yml go arm + packages/core/templates/go/github-actions-ci.yml exact-pinned go-version: '1.22.0' + golangci-lint@v1.55.2 — IDENTICAL on both surfaces
F11 (rules-lock core field set) packages/core/installer/types.ts:36-43 unchanged — rules-lock.go.json carries all 6 core fields + per-lane backend, note

§2 §1.3 LOAD-BEARING ENVIRONMENT FACT — local vs runner evidence split

go and golangci-lint are ABSENT from the execution container (probed 2026-07-25: command -v go → rc=1; command -v golangci-lint → rc=1). This is the cargo precedent verbatim (setup.d/46-cargo.sh:295-304).

  • What the lane proves locally: degrade pathsetup.d/47-go.sh:215-225 prints «go or golangci-lint not on PATH … firing NOT proven (degrade, NOT green)» with the §1.3 honest REPORTING label «insufficient (tool absent)», rc=0.
  • Where the E1 red/green proof actually lands: the pinned go CI arm on the GitHub runner (.github/workflows/audit-self.yml go arm). The arm installs exact-pinned go 1.22.0 + golangci-lint v1.55.2, runs bash install.sh go into a scratch fixture, and asserts all three artefacts landed (.golangci.yml, .github/workflows/getff-go.yml, rules-lock.go.json).
  • T-EW-C posture (binding): until the runner arm is green AND linked here, E1 is unproven — say so plainly. PROVEN ON THE RUNNER: audit-self / «Principles as meta-tests (Phase 2)» — go lane live-fire (commit 64caa8509e). That job's Run getff go lane live-fire (adapter-jig J3) step printed ✓ golangci-lint fired RED on the planted violation (forbidigo os.Getenv ban live), ✓ golangci-lint clean control GREEN — no diagnostic on conforming code (config discriminates) and enforcement is live, on the exact-pinned go 1.22.0 + golangci-lint v1.55.2 toolchain. Scope of the link, stated plainly: it covers 64caa8509e, not the current head — the two later commits (852e1443bf, bc529ed28c) touch only the arm-P1 test population, three comments and the workflow's cache path, and change nothing the self-check executes or the config it resolves. No runner has spoken for the current head, and this PR does not pretend otherwise: the GitHub Actions incident opened 2026-08-06T15:22Z throttled webhook triggers to ~15%, and zero workflow runs were created for either 852e1443bf or bc529ed28c (actions/runs?head_sha=…total_count: 0; the only two check-runs on the head are the Socket app's). Rather than wait the outage out, the owner merged via an --admin override. The substitute evidence is the local CI-equivalent gate sweep scripts/run-local-ci-sweep.sh --full --base origin/staging, which aggregates the audit-self.yml gate set for exactly this case (its header cites PR S3: revive tool-bootstrap layer + static stack column (modular-install-fullpack) #724, «pushed, CI reddened on a gate I didn't re-run»): 12 gates green — actionlint, md-ci-only, meta-all-wired, format-check, render-check, typecheck, byte-identical, agnosticism, install-sh-suite, vitest-principles (342 passed / 1 skipped), vitest-render (2), vitest-hooks (1044). One caveat recorded rather than buried: on the first pass vitest-hooks went RED on two tests (hooks/check-worker-dispatch-channel.test.ts, hooks/validate-prompt.test.ts, both the C1: linked worktree … PATH scrubbed case). Diagnosed as a load-related timeout flake on three independent signals — neither file references anything in this diff, the failure mode was a 5000ms timeout at 9.9s/10.6s rather than an assertion, and the same code passes 39/39 at --testTimeout=30000 — and the sweep is fail-fast, so vitest-principles and vitest-render were re-run separately. What none of this covers, stated so the record is not read as a verdict it never received: the go arm's live-fire did NOT re-run on the merged SHA. The next audit-self run on staging is what re-establishes E1 there; if it reddens on the go arm, this row is where to look.

§3 §2.1 hard-node resolution — go Tier-1 host derivation vs frozen row F3

go has NO registry metadata document carrying homepage/repository. The module path itself (github.com/user/repo) IS the identity. Per F3's binding wording — «Adapters FEED tier1For; they never re-implement or bypass it» — the go adapter:

  1. SYNTHESIZES the {homepage, repository}-shaped raw URLs inside readInstalledMeta (packages/core/research/ecosystem-go.ts:78-122) from the module path — https://${modulePath} and git+https://${modulePath}.git. This is exactly what npm/cargo/python's readInstalledMeta do, just from a different source.
  2. HANDS them to the unchanged tier1For pipeline at allowlist-resolver.ts:189-243. The pipeline canonicalizes → rejects IP / single-label / punycode / multi-tenant apex → empty-hosts miss.
  3. DOES NOT add a go-shaped branch inside tier1For, DOES NOT skip the pipeline for go, DOES NOT pre-canonicalize or pre-reject the URL.

T-AJ3-A falsifier satisfied: the adapter's job is to FEED, the pipeline's job is to REJECT/ACCEPT — verified by paired-negative ecosystem-go.test.ts:135-160 (multi-tenant apex github.com synthesizes → feeds pipeline → empty-hosts miss, exactly as it does for npm/cargo/python).

Sub-node (arm B3 direct-deps-only): go.mod require blocks mark transitive dependencies with // indirect. listDirectDeps (ecosystem-go.ts:124-145) parses go.mod and filters // indirect out, so the direct-dep gate does not silently widen.

§4 22-arm mapping (§1.2 obligation)

For each canonical arm: go-side evidence OR explicit park rationale. NONE silently dropped.

§4.1 Parsing / resolution

  • A1 no-new-throw-on-prewired-path — SWEPT-CLEAN. ecosystem-name.ts:22 adds 'go' to KNOWN_ECOSYSTEM_PREFIXES; parseEcosystemName('go:github.com/user/repo') now resolves to {ecosystem:'go', bareName:'github.com/user/repo'} without a throw. Pinned by a paired it('go: prefix parses …') case in ecosystem-name.test.ts (added in this rework pass — the pre-rework draft claimed the test was extended when it was not; corrected here per the auto-review blocking finding).
  • A2 polyglot-precedence-pinned — SWEPT-CLEAN. The detector (packages/core/detector/read-python-cargo.ts) gains a go.mod branch; precedence is pinned by ordering: npm → python → cargo → go → unknown. packages/core/detector/stack-exhaustiveness.test.ts extends to cover go.

§4.2 Trust

  • B1 tier1-trust-poisoned-negative — SWEPT-CLEAN. ecosystem-go.test.ts:135-160 synthesizes a poisoned multi-tenant apex (github.com/attacker/payload), feeds tier1For, asserts an empty-hosts MISS (Tier-1 never auto-trusts a multi-tenant apex for go, same as npm/cargo/python).
  • B2 value-guard-containment — NOT APPLICABLE — go's readInstalledMeta synthesizes URLs from a dep NAME without any FS join, so the VALUE-traversal surface (resolvedWithinRoot) has no go analogue. The NAME-surface isUnsafeDepName is wired (ecosystem-go.ts:39-46); the precondition tripwire at ecosystem-adapter-precondition.test.ts detects the textual signal automatically (H3 population-equality — go joins the population).
  • B3 direct-deps-only — SWEPT-CLEAN. ecosystem-go.ts:124-145 listDirectDeps parses go.mod require blocks and filters out // indirect lines. Verified by paired-negative ecosystem-go.test.ts:101-132 (mixed direct + indirect → indirect excluded).

§4.3 Delivery cells

  • C1 delivery-cell-matrix-complete — SWEPT-CLEAN. setup.d/47-go.sh ships all three cells (fresh-copy at :73-79, structural-merge-or-REFUSE at :85-145, REFUSE + namespaced reference as the fallback inside the same block) + idempotent re-run + .override.md refresh escape hatch. Mirrors setup.d/46-cargo.sh.
  • C2 no-consumer-manifest-mutation — SWEPT-CLEAN. The lane copies templates into the consumer tree via _go_copy_or_refresh; it never edits the consumer's go.mod. The REFUSE cell fires when a consumer .golangci.yml is already present (brownfield-golangci snapshot baseline cements the byte-identity of the REFUSE branch).
  • C3 snapshot-exclusion-no-drift-mask — SWEPT-CLEAN. tests/install-sh/snapshot.sh extends its exclusion set with -not -name '.getff-go-install.log' and -not -name 'rules-lock.go.json' — each excluded file is a getff emission (not a drift-mask).
  • C4 no-orphan-residue — SWEPT-CLEAN. setup.d/47-go.sh:285-305 report_getff_orphans go .golangci.yml getff-golangci.yml .github/workflows/getff-go.yml runs on every refresh to surface any orphaned getff artefact after a consumer-side delete.

§4.4 Lock integrity

  • D1 lock-never-stale-on-any-pass — SWEPT-CLEAN. tests/install-sh/rules-lock-schema-parity.test.sh:60-80 arm (2b): scratch install with bash "$INSTALL" go emits rules-lock.go.json; re-run on the same fixture is idempotent (no stale diff).
  • D2 no-silent-fingerprint-degrade — SWEPT-CLEAN. setup.d/47-go.sh:147-157 _go_write_rules_lock uses the algorithm-prefixed fingerprint ladder sha256 → shasum → md5/md5sum. No silent degrade: each step fails loudly if the binary is missing, never falls through to a weaker algorithm silently.
  • D3 lock-schema-parity — SWEPT-CLEAN. rules-lock.go.json carries all 6 F11 core fields {schemaVersion, framework, version, ruleIds, emittedAt, sourceFingerprint} + per-lane backend + note. Verified by rules-lock-schema-parity.test.sh:60-80 asserting the core-set is a subset of emitted keys.

§4.5 Firing

  • E1 scratch-consumer-red-green-pair — PARKED LOCALLY, PROVEN ON RUNNER. §1.3: go/golangci-lint absent locally. The lane's _go_firing_self_check (setup.d/47-go.sh:159-225) plants os.Getenv("HOME") in mktemp -d, runs golangci-lint run --enable forbidigo ./..., asserts RED on the violation + GREEN on a paired clean control (os.Args). Locally prints «insufficient (tool absent)» per cargo precedent. The runner arm (.github/workflows/audit-self.yml go arm) fires the same self-check under exact-pinned toolchain — PROVEN ON THE RUNNER: audit-self / «Principles as meta-tests (Phase 2)» — go lane live-fire (commit 64caa8509e). That job's Run getff go lane live-fire (adapter-jig J3) step printed ✓ golangci-lint fired RED on the planted violation (forbidigo os.Getenv ban live), ✓ golangci-lint clean control GREEN — no diagnostic on conforming code (config discriminates) and enforcement is live, on the exact-pinned go 1.22.0 + golangci-lint v1.55.2 toolchain. Scope of the link, stated plainly: it covers 64caa8509e, not the current head — the two later commits (852e1443bf, bc529ed28c) touch only the arm-P1 test population, three comments and the workflow's cache path, and change nothing the self-check executes or the config it resolves. A re-run on the current head is pending the GitHub Actions incident opened 2026-08-06T15:22Z (webhook triggers throttled, pushes not creating workflow runs); merge is gated on it, so the runner will have spoken for the merged SHA before this lands.
  • E2 self-check-resolves-delivered-config — SWEPT-CLEAN. _go_firing_self_check calls _go_delivered_golangci_path (setup.d/47-go.sh:65-72) which resolves the delivered .golangci.yml (fresh cell) or getff-golangci.yml (REFUSE cell) — never a path the consumer could plant.
  • E3 toolchain-freshness-vs-evidencePARKED per §3 park-don't-guess contract. The cargo precedent implements this arm through a backend capability-matrix at packages/core/backends/cargo/capability-matrix.json + firing-runner.ts. Whether a stamped family owes the same backends/go/ structure is unsettled in the umbrella — see §5 below.

§4.6 CI pinning

  • P1 pinned-toolchain-in-ci — SWEPT-CLEAN. .github/workflows/audit-self.yml go arm pins actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with go-version: '1.22.0' (exact, ci-tool-pinning.md Rule A) and go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2 (exact @<tag>). The F10 two-surface parity is ENFORCED, not asserted: go-toolchain and golangci-lint are registered in the arm's own population (packages/core/hooks/pin-parity.test.ts:60-71, per-tool consumerSurfaces), so a pin edited on one surface and not the others turns the REAL-tree test RED (verified by mutation: 1.22.0 -> 1.23.0 on the delivered template yields go-toolchain: pin divergence — framework pins {1.22.0}, consumer pins {1.23.0}). Before round 3 this row was a prose claim guarded only by a comment at setup.d/47-go.sh:143 — the fidelity audit's MAJOR.

§4.7 Type-shape / wiring atomicity

  • G1 type-widening-exhaustiveness — SWEPT-CLEAN. packages/core/detector/types.ts Stack union widens to include 'go'. packages/core/detector/stack-exhaustiveness.test.ts extends the switch-exhaustiveness assertion over the widened union.
  • G2 all-callsites-migrated-atomically — SWEPT-CLEAN. packages/core/synthesizer/resolve-ctx.ts threads the go adapter into resolveCtxForRoot in the SAME commit (dfbdc045). No intermediate commit leaves the union widened but the resolver un-wired — verified by the unwired-debt tripwire at the next bullet.
  • G3 zero-skill-core-edits — SWEPT-CLEAN. ZERO edits under .claude/skills/** or .claude/orchestrator-prompts/** in this PR. git diff --name-only origin/staging..HEAD -- .claude/skills/ .claude/orchestrator-prompts/ returns EMPTY.

§4.8 Tripwire lockstep

  • H1 baseline-debt-lockstep — SWEPT-CLEAN. packages/core/research/ecosystem-unwired-debt.test.ts:106 BASELINE = 0 stays 0 — goAdapter is WIRED in the same PR (commit dfbdc045), so the population count never exceeds baseline. npx vitest run packages/core/research/ecosystem-unwired-debt.test.ts passes (5/5).
  • H2 tripwire-predicate-no-conjunctive-narrowing — SWEPT-CLEAN. The unwired-debt predicate is unchanged — goAdapter joins the population but the predicate (unwired === true) is not narrowed to exclude it.
  • H3 tripwire-population-equality — SWEPT-CLEAN. packages/core/research/ecosystem-adapter-precondition.test.ts and ecosystem-unwired-debt.test.ts automatically include goAdapter in their populations (regex-detected by F5 idiom). npx vitest run over all 4 tripwire suites → 21/21 pass.

§5 E3 park — backends/go/ structure is unsettled in the umbrella

E3 (toolchain-freshness-vs-evidence) is the one arm whose applicability to a NEW stamped family is genuinely ambiguous. The cargo precedent implements E3 via packages/core/backends/cargo/capability-matrix.json + firing-runner.ts. Whether a stamped family owes the same backends/<ecosystem>/ structure is NOT settled by the umbrella contract — it sizes the stage and is not the executor's call to make silently (kickoff §1.2: «If an arm's applicability is genuinely ambiguous, PARK it rather than deciding it»).

Two options, both legitimate, neither chosen here:

  • Option A — lane-firing only (this PR's posture). E3 is satisfied by the lane's firing self-check + the runner arm. No backends/go/ structure ships. Pro: matches the cargo lane's own surface BEFORE its backend landed; con: leaves a checkToolchainFreshness analogue unfired for go.
  • Option B — ship backends/go/capability-matrix.json + firing-runner. Mirrors cargo's E3 implementation literally. Pro: full structural parity with cargo; con: introduces a second surface (capability matrix + firing runner) that the umbrella has not bound the go family to.

Parked per kickoff §3. Surfaced here for the cold-review pass and maintainer judgment.

§6 §1.7 self-reflexive note

This section complies with phase-research-coverage.md §1.7 shape: each discipline is named with file.ext:line evidence. Header form (H3 + literal applied) satisfies the discipline-self-check.yml:57,63 regex pair.

§1.7 Forward-check applied

  • no-paid-llm-in-ci.md §1 (/.claude/rules/no-paid-llm-in-ci.md:22): the go CI arm is bash install.sh go + golangci-lint run — deterministic, zero API-billed calls.
  • ci-tool-pinning.md Rule A (/.claude/rules/ci-tool-pinning.md): every CI tool exact-pinned. Framework surface .github/workflows/audit-self.yml:275-296 and consumer mirror packages/core/templates/go/github-actions-ci.yml:46-53 carry IDENTICAL pins (actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0, go-version: '1.22.0', golangci-lint@v1.55.2).
  • build-first-reuse-default.md §1 (/.claude/rules/build-first-reuse-default.md): ADOPT-MIRROR verdict. The lane shape is setup.d/46-cargo.sh reused verbatim where the ecosystems are structurally identical (cell grammar, fingerprint ladder, rules-lock schema); the adapter is unique to go's module-path identity model (§2.1 hard node). No BUILD-without-search violation; precedent is the merged cargo lane.
  • doc-authority-hierarchy.md §2-§3 (/.claude/rules/doc-authority-hierarchy.md): new template files under packages/core/templates/go/ are templates (schema-bearing, not prose); the lane setup.d/47-go.sh is shell code (function names are the documentation per «documents lie; tests don't»). No new canonical doc requiring an Authoritative-for header was introduced.
  • destination-environment-verification.md §4 (/.claude/rules/destination-environment-verification.md): §2 of this PR body names the §1.3 LOAD-BEARING ENVIRONMENT FACT explicitly. The container cannot prove E1 locally; the runner arm is the proving ground. The label «insufficient (tool absent)» is the honest reporting label, never a DoD exit.
  • research-source-trust.md §5 (/.claude/rules/research-source-trust.md): the go adapter (packages/core/research/ecosystem-go.ts:1-11) carries the offline-determinism header comment; zero network, zero binary invocation. Mirrors ecosystem-npm.ts / ecosystem-cargo.ts / ecosystem-python.ts.
  • rule-enforcement-channel-selection.md §1 (/.claude/rules/rule-enforcement-channel-selection.md): the new lane is mechanically-testable shell (setup.d/47-go.sh + tests/install-sh/rules-lock-schema-parity.test.sh arm 2b) → gate, not injection.
  • zcode-parity-doctrine.md §2 (.claude/rules/zcode-parity-doctrine.md): NOT APPLICABLE — this PR ships no new .claude/hooks/** or plugin/hooks/** artefact; the lane is install.sh surface only.
  • ai-laziness-traps.md §2 (.claude/rules/ai-laziness-traps.md):
    • T2 — the methodology was RUN, not designed: every arm above cites a concrete test or file:line invocation, not «would detect».
    • T15 — this §1.7 IS the self-application; §4 the 22-arm mapping is the framework's own discipline applied to itself.
    • T20 — every recommendation in §5 (E3 park) is preceded by file:line evidence (packages/core/backends/cargo/capability-matrix.json).

§1.7 Backward-check applied

The change-class is: «stamping a new ecosystem adapter family end-to-end through the conformance jig».

  • packages/core/research/ecosystem-npm.ts — SWEPT-CLEAN. The npm adapter is unchanged; its 3-method seam is the same F1 surface goAdapter implements.
  • packages/core/research/ecosystem-cargo.ts — SWEPT-CLEAN. The cargo adapter is unchanged; setup.d/47-go.sh mirrors setup.d/46-cargo.sh's shape where structurally identical, diverges only on go's module-path identity (no registry metadata).
  • packages/core/research/ecosystem-python.ts — SWEPT-CLEAN. Python adapter unchanged.
  • packages/core/research/allowlist-resolver.ts — SWEPT-CLEAN. The frozen pipeline (:189-243) is UNCHANGED; the go adapter FEEDS it via readInstalledMeta synthesis (§3 of this PR body).
  • setup.d/45-python.sh, setup.d/46-cargo.sh — SWEPT-CLEAN. Lane shape mirrors; no lane was edited as a side-effect of go.
  • .github/workflows/audit-self.yml — EXTENDED in place. Pre-existing rust arm (:250-274) is UNCHANGED; the go arm (:275-296 approx) is added AFTER it. CI green expected to remain unchanged on the rust arm.
  • packages/core/templates/python/, packages/core/templates/cargo/ — SWEPT-CLEAN. The new packages/core/templates/go/ directory mirrors the existing pair's structure (template + github-actions-ci.yml).
  • packages/core/principles/33-adapter-jig-arm-registry.ts:63-93 — SWEPT-CLEAN. The CANONICAL_ARMS array is UNCHANGED — J3 stamps a family through the existing arm set; no arm was added, removed, or narrowed.

Population-vs-baseline reconciliation: the unwired-debt tripwire's BASELINE (ecosystem-unwired-debt.test.ts:106) is 0 AND stays 0 because goAdapter is wired in this same PR (G2 atomicity). There is no point in the commit history where the population exceeds baseline.

§7 Self-application (T15) — the framework's own discipline applied to itself

The framework's thesis is that every rule must be an executable artifact failing at the earliest reachable channel. This PR dogfoods that thesis on a new family:

  • F8 firing self-check at setup.d/47-go.sh:159-225 — executable, fires at bash install.sh go (install-time channel).
  • H1 baseline lockstep at packages/core/research/ecosystem-unwired-debt.test.ts:106 — executable, fires in vitest (CI channel).
  • H3 population equality at packages/core/research/ecosystem-adapter-precondition.test.ts — executable, fires in vitest.
  • D3 lock schema parity at tests/install-sh/rules-lock-schema-parity.test.sh arm 2b — executable, fires in bash test harness.
  • F9 snapshot byte-identity at tests/install-sh/snapshot.sh — executable, fires in SNAPSHOT_MODE=compare.

No "trust me" assertions. Every claim this PR makes is backed by a test that fails loudly if the claim becomes false.

§8 Test plan

Run locally (post-merge-forward):

SNAPSHOT_MODE=compare bash tests/install-sh/snapshot.sh
  → 15 pass / 0 fail

npx vitest run packages/core/research/ecosystem-go.test.ts
  → 12 passed (12)

bash tests/install-sh/rules-lock-schema-parity.test.sh
  → 9 passed, 0 failed

npx vitest run packages/core/research/ecosystem-unwired-debt.test.ts \
                packages/core/research/ecosystem-adapter-precondition.test.ts \
                packages/core/research/ecosystem-name.test.ts \
                packages/core/detector/stack-exhaustiveness.test.ts
  → 4 files, 21 passed

On PR open: CI runner arm .github/workflows/audit-self.yml go arm proves E1 under pinned toolchain — link the run URL in §2 above (T-EW-C).

§9 Notes for the harvest / PR-create step

  • Branch: feature/adapter-jig-j3-d4db43 (4 commits ahead of staging: 3 feature + 1 merge-forward b4435630).
  • Base: staging.
  • The container could NOT push (no TCP to github.com per §1.3, gh unauthed). Egress via Channel A of egress-no-api-bypass.md (host-pull + host git push after rebasing on live origin/staging — already done locally as b4435630, but the host should re-fetch and re-rebase if staging has moved further).
  • After PR open: edit §2 of this body to paste the CI runner arm URL for the E1 evidence link.

Cold-review: invoke agents/adapter-jig-reviewer.md per the J1 contract. Reviewer's read-only authority covers the F1-F11 frozen rows + the 22-arm mapping in §4.

Harvest addendum (orchestrator, 2026-07-26)

Merge is intentionally held. The pre-egress cold audit (agents/fidelity-auditor.md) ran Round 1 against the mid-rework diff and returned REVISE; all 5 findings were fixed and hand-verified (real actions/setup-go@41dfa10 pin restoring F10 two-surface parity; the live-fire step now failing on the lane's own /SILENT/OVER-BROAD/NOT proven markers AND asserting the positive «enforcement is live» line; single-label rejection returned to tier1For; same-step GITHUB_PATH hazard removed; the go: prefix test committed as b4fab802 so §4.1's citation is true against the diff). Round 2 over this final diff has NOT yet run — the operator paused the session on quota. No ## Fidelity verdict section is present, so the required fidelity-verdict-in-pr-body check stays RED and blocks merge — that is the fail-closed hold working as designed, not a CI accident. On resume: fidelity Round 2 (cap rule: REVISE → STOP + escalate) → GO block added → auto-merge only after the body is final (the #1162 race lesson). The §5 E3 park is the one owner decision awaiting the operator: worker recommends Option A (no backends/go/ matrix in this PR; cargo precedent — matrix shipped separately from its lane).

Fidelity verdict

FIDELITY: GO
Basis: .claude/orchestrator-prompts/adapter-jig-j3/kickoff.md
Round: 3
Audited-SHA: bc529ed
Evidence: packages/core/hooks/pin-parity.test.ts:60-71 (go-toolchain + golangci-lint joined the arm-P1 population with per-tool consumerSurfaces); packages/core/hooks/pin-parity.test.ts:145-159 (the live-population assertion and the REAL-tree mirror now loop over all four tools, so a one-sided go pin edit goes RED); packages/core/principles/33-adapter-jig-arm-registry.ts:600-603 (the canonical arm list's P1 scope prose follows that population); .github/workflows/audit-self.yml:304 (~/go/bin replaces the empty ${{ env.GOBIN }}); packages/core/research/ecosystem-go.test.ts:3 (provenance points at the tracked kickoff); packages/core/synthesizer/resolve-ctx.ts:40 (doc comment carries the go rung it selects at :62)
Findings: MINOR — no go entry-lane suite: go-side arm markers cover B1/B2/B3 (packages/core/research/ecosystem-go.test.ts:47,64,158,181,199) where python and cargo ship tests/install-sh/python-entry-lane.test.sh:166 and tests/install-sh/cargo-entry-lane.test.sh:119. Carried deliberately: kickoff §2's five-deliverable list does not name per-arm suites, and the E1/E2 evidence is the live runner arm linked in §4.5 rather than a committed lane script. MINOR — the registry's collapsed phrase «the go toolchain + golangci-lint (J3), whose consumer half is the delivered CI template plus the lane's REFUSE-path hint» (packages/core/principles/33-adapter-jig-arm-registry.ts:600-601) reads as if both tools mirror on both surfaces, while go-toolchain mirrors only on the CI template (packages/core/hooks/pin-parity.test.ts:75) and only golangci-lint adds setup.d/47-go.sh (:82); the following sentence resolves it, so the prose is compressed, not wrong.

Round history: Round 1 REVISE (5 findings, fixed pre-egress) → Round 2 REVISE over 64caa85 (1 MAJOR: arm P1 / F10 two-surface pin parity had no go-side enforcement — go pinned on both surfaces, population unextended, sync guarded by a prose comment; + 4 MINOR) → Round 3 GO over 852e144, refreshed onto bc529ed by a narrow cold delta check after a comment-only scope-neutral commit (.claude/rules/cold-seat-economy.md §1). Per-round watch-list verdicts are in ## Review findings.

Review findings

Watch-list

id criterion why defect site reintroduction tell
W-1 kickoff §2 deliverable 4 — F10 two-surface pin parity (arm P1) enforced, not commented a framework/consumer pin divergence ships consumers a toolchain different from the evidence the framework fired against; both lines stay individually "pinned", so the per-line gate at checks/unpinned-tool-install.ts cannot see it closed in round 3 — packages/core/hooks/pin-parity.test.ts:60-71,145-159 (defect site was :47-53) a golangci-lint or go-version value edited on any one of .github/workflows/audit-self.yml:292,310 / packages/core/templates/go/github-actions-ci.yml:48,53 / setup.d/47-go.sh:147,306 without the same string moving on all of them; or a round that removes a go entry from TRACKED_TOOLS or drops it from the REAL-tree loop
W-2 kickoff §2.1 + T-AJ3-A — the adapter FEEDS tier1For; every accept/reject decision stays in the frozen pipeline a host-shape test inside readInstalledMeta short-circuits the frozen canonicalize/reject chain; arm B1 then passes without the pipeline ever running (partial F3 bypass) packages/core/research/ecosystem-go.ts:150-160 — a single-label return null lived here and was removed pre-egress any host/hostname/includes('.')/new URL(...) inspection, or any second return null beyond the isUnsafeDepName name-guard, reappearing in readInstalledMeta, however phrased
W-3 kickoff §1.1 F8 — plant in mktemp -d only, LOUD degrade when the tool is absent, rc=0 on every branch a self-check that writes into the consumer tree or aborts the install turns a proof into an outage; a silent degrade makes "tool absent" read as green none — preventive (setup.d/47-go.sh:262-320 conforms) a write path under $PROJECT_ROOT inside _go_firing_self_check, a return 1/exit on any branch, or the insufficient (tool absent) / NOT proven strings being softened or dropped from the degrade branch
W-4 kickoff §2 deliverable 5 / §4 — BASELINE stays 0 because the adapter is wired in the same PR an adapter that lands unwired is dead code a later umbrella silently forgets; the tripwire only holds under strict === none — preventive (packages/core/research/ecosystem-unwired-debt.test.ts:106 = 0; wiring at packages/core/synthesizer/resolve-ctx.ts:62) const BASELINE becoming any non-zero literal, or the literal adapter: goAdapter at resolve-ctx.ts:62 being replaced by a dynamic/registry lookup (which evades isWired's grep and would need a BASELINE bump instead)
W-5 kickoff §2 deliverable 4 + T-AJ3-C — the CI arm must make the go firing path EXECUTE, not merely install a toolchain _go_firing_self_check returns 0 by contract on every branch, so a step relying on exit code alone goes green over a SILENT or OVER-BROAD config — the arm becomes a claim, not a proof none — preventive (.github/workflows/audit-self.yml:346,353) the grep -E 'SILENT|OVER-BROAD|NOT proven|✗' failure-marker check or the positive grep -F 'enforcement is live' check being removed, made non-fatal, or reduced back to [ -f ... ] existence assertions
W-6 kickoff §2 / arm E1 — the delivered config must discriminate: RED on the planted violation, GREEN on the clean control under the pinned golangci-lint v1.x an unknown key is dropped silently, leaving the regex empty — which matches everything, so the config fires on conforming code and enforcement is fake in the loudest way packages/core/templates/go/.golangci.yml:31 — the forbid key was pattern: instead of p: (CI run 31093381580); fixed at 64caa8509e the forbidigo entry key changing from p: to pattern: (a plausible "modernisation" to the v2 schema) without the golangci-lint@v1.55.2 pin moving in the same edit, on any of the four pin sites
W-7 kickoff §1.2 + §3 trigger 2 — E3 toolchain-freshness-vs-evidence is PARKED, not decided parking sizes the stage; silently answering it (either by building a backends/go/ capability-matrix or by declaring E3 not-applicable) takes an owner decision the worker was told not to make none — preventive (.github/workflows/audit-self.yml:275-276 records the park and points at §5 of this body) a packages/core/backends/go/ directory or capability-matrix.json appearing, a test:backends-style include-allowlist entry for go, or the park note being rewritten into a verdict
W-8 kickoff §0/§1.2 — the arm registry is the canonical arm list; its P1 scope prose must match the tracked population a registry that names a narrower population than the arm enforces re-teaches the next stamped family the old, smaller scope closed in the round-3 delta refresh — packages/core/principles/33-adapter-jig-arm-registry.ts:600-603 (stale when introduced by round 2's widening) the P1 comment's tool enumeration diverging from TRACKED_TOOLS in packages/core/hooks/pin-parity.test.ts in either direction — a tool added to one and not the other

Round 2: W-1 REINTRODUCED (packages/core/hooks/pin-parity.test.ts:47-53) · W-2 CLEAN (packages/core/research/ecosystem-go.ts:150-160) · W-3 CLEAN (setup.d/47-go.sh:262-320) · W-4 CLEAN (packages/core/research/ecosystem-unwired-debt.test.ts:106) · W-5 CLEAN (.github/workflows/audit-self.yml:342,349) · W-6 CLEAN (packages/core/templates/go/.golangci.yml:26) · W-7 CLEAN (.github/workflows/audit-self.yml:275-277) · W-8 n/a (item did not exist)

Round 3: W-1 CLEAN · W-2 N/A (surface absent from the round's diff; spot-verified at head — no host inspection, single return null at packages/core/research/ecosystem-go.ts:143) · W-3 N/A (surface absent from the round's diff) · W-4 CLEAN · W-5 CLEAN · W-6 N/A (surface absent from the round's diff) · W-7 CLEAN · W-8 REINTRODUCED at 852e144, then CLEAN at bc529ed (delta refresh)

Watch-list

id criterion why defect site reintroduction tell
W-1 kickoff §2 deliverable 4 — F10 two-surface pin parity (arm P1) enforced, not commented a framework/consumer pin divergence ships consumers a toolchain different from the evidence the framework fired against; both lines stay individually "pinned", so the per-line gate at checks/unpinned-tool-install.ts cannot see it packages/core/hooks/pin-parity.test.ts:47-53 (TRACKED_TOOLS lacks a go row this round) a golangci-lint or go-version value edited on any one of .github/workflows/audit-self.yml:292,306 / packages/core/templates/go/github-actions-ci.yml:48,53 / setup.d/47-go.sh:147,306 without the same string moving on all of them; or a later round that adds go to the P1 population and then narrows it back
W-2 kickoff §2.1 + T-AJ3-A — the adapter FEEDS tier1For; every accept/reject decision stays in the frozen pipeline a host-shape test inside readInstalledMeta short-circuits the frozen canonicalize/reject chain; arm B1 then passes without the pipeline ever running (partial F3 bypass) packages/core/research/ecosystem-go.ts:150-160 — a single-label return null lived here and was removed this round any host/hostname/includes('.')/URL(...) inspection, or any second return null beyond the isUnsafeDepName name-guard, reappearing in readInstalledMeta, however phrased
W-3 kickoff §1.1 F8 — plant in mktemp -d only, LOUD degrade when the tool is absent, rc=0 on every branch a self-check that writes into the consumer tree or aborts the install turns a proof into an outage; a silent degrade makes "tool absent" read as green none — preventive (setup.d/47-go.sh:262-320 conforms) a write path under $PROJECT_ROOT inside _go_firing_self_check, a return 1/exit on any branch, or the insufficient (tool absent) / NOT proven strings being softened or dropped from the degrade branch
W-4 kickoff §2 deliverable 5 / §4 — BASELINE stays 0 because the adapter is wired in the same PR an adapter that lands unwired is dead code a later umbrella silently forgets; the tripwire only holds under strict === none — preventive (ecosystem-unwired-debt.test.ts:106 = 0; wiring at resolve-ctx.ts:61) const BASELINE becoming any non-zero literal, or the adapter: goAdapter textual form at resolve-ctx.ts:61 being replaced by dynamic/registry lookup (which evades isWired's grep and would need a BASELINE bump instead)
W-5 kickoff §2 deliverable 4 + T-AJ3-C — the CI arm must make the go firing path EXECUTE, not merely install a toolchain _go_firing_self_check returns 0 by contract on every branch, so a step relying on exit code alone goes green over a SILENT or OVER-BROAD config — the arm becomes a claim, not a proof .github/workflows/audit-self.yml:342,349 — an earlier round asserted artefact existence only (MAJOR 2, fixed this round) the grep -E 'SILENT|OVER-BROAD|NOT proven...|✗' failure-marker check or the positive grep -F 'enforcement is live' check being removed, made non-fatal, or reduced back to [ -f ... ] existence assertions
W-6 kickoff §2 / arm E1 — the delivered config must discriminate: RED on the planted violation, GREEN on the clean control under the pinned golangci-lint v1.x an unknown key is dropped silently, leaving the regex empty — which matches everything, so the config fires on conforming code and enforcement is fake in the loudest way packages/core/templates/go/.golangci.yml:26 — the key was pattern: instead of p: (CI run 31093381580); fixed in 64caa8509e the forbidigo entry key changing from p: to pattern: (a plausible "modernisation" to the v2 schema) without the golangci-lint@v1.55.2 pin moving in the same edit, on any of the four pin sites
W-7 kickoff §1.2 + §3 trigger 2 — E3 toolchain-freshness-vs-evidence is PARKED, not decided parking sizes the stage; silently answering it (either by building a backends/go/ capability-matrix or by declaring E3 not-applicable) takes an owner decision the worker was told not to make none — preventive (.github/workflows/audit-self.yml:275-277 records the park and points at the PR body) a packages/core/backends/go/ directory or capability-matrix.json appearing, a test:backends-style include-allowlist entry for go, or the park note being rewritten into a verdict

Round 2: W-1 REINTRODUCED (packages/core/hooks/pin-parity.test.ts:47-53) · W-2 CLEAN (packages/core/research/ecosystem-go.ts:150-160) · W-3 CLEAN (setup.d/47-go.sh:262-320) · W-4 CLEAN (packages/core/research/ecosystem-unwired-debt.test.ts:106) · W-5 CLEAN (.github/workflows/audit-self.yml:342,349) · W-6 CLEAN (packages/core/templates/go/.golangci.yml:26) · W-7 CLEAN (.github/workflows/audit-self.yml:275-277)

Prior-art: prior-art-evaluations.md#226 (conformance-kit SSOT entry landed with J1 #1087 — this PR is the jig's first stamped family; the go adapter follows the frozen F1-F11 contract that entry governs, BUILD verdict already adjudicated there, no new problem-class).

Test added 6 commits July 25, 2026 17:19
…iring (J3)

J3 stage 1: stamp the `go` family end-to-end through the conformance jig. This
commit ships Commit A of the 5-commit atomic plan — the adapter core + atomic
wiring (G2/H1 lockstep).

§2.1 hard node (docs/superpowers/specs/2026-07-22-adapter-jig-design.md §2.1):
go has NO registry metadata document; the module path IS the identity. The
adapter SYNTHESIZES `{homepage, repository}`-shaped raw URLs from the module
path inside `readInstalledMeta` and feeds them to the unchanged `tier1For`
pipeline (F3 frozen — adapters FEED, never bypass). Single-label first segments
return null (Tier-1 miss, falls through to Tier-0/Tier-2). The adapter does
NOT short-circuit `tier1For`'s rejection chain — no pre-canonicalization, no
pre-rejection (T-AJ3-A falsifier).

Deliverables in this commit:
- `packages/core/research/ecosystem-go.ts` — goAdapter (F5 typed-const idiom).
  `listDirectDeps` parses go.mod require blocks/single-line forms, filters
  `// indirect` (B3). `readInstalledMeta` synthesizes URLs from module paths.
  Fail-closed parser (unterminated block → empty set, never throws).
- `packages/core/research/ecosystem-go.test.ts` — paired B1/B2/B3 positives+
  negatives. Documents the B1 asymmetry (evil.example.com is single-tenant;
  the B1 negative catches a github.com-substring extractor, NOT a multi-tenant
  bypass of github.com/user/repo itself which tier1For rejects anyway).
- `packages/core/research/ecosystem-name.ts:22` — `KNOWN_ECOSYSTEM_PREFIXES`
  widened with `'go'` (F4 in-scope — extending the prefix set is explicitly
  permitted).
- `packages/core/synthesizer/resolve-ctx.ts` — `goAdapter` threaded into
  `resolveCtxForRoot` via literal `adapter: goAdapter` (G2 — registry form
  evades the unwired-debt grep, must be explicit literal).
- `packages/core/detector/types.ts` — Stack union widened with `'go'`.
- `packages/core/detector/stack-exhaustiveness.test.ts` — G1 sentinel updated
  with the new `'go'` case + variant + label (RED before widening, GREEN now).
- `packages/core/detector/read-python-cargo.ts` — go.mod → 'go' detection
  branch mirroring the Cargo.toml → 'cargo' branch.
- `packages/core/research/ecosystem-unwired-debt.test.ts` — sanity test
  updated to assert all FOUR shipped adapters are wired (npmAdapter +
  cargoAdapter + pipAdapter + goAdapter). BASELINE stays 0.

Atomic (G2/H1 lockstep): landing the adapter UNWIRED would push BASELINE from
0 to 1 and trip `ecosystem-unwired-debt.test.ts:106` mid-PR. The wiring MUST
land in the same commit.

Acceptance verification (local):
- `npx tsc --noEmit` — GREEN (G1 sentinel compiles with the new variant; no
  Stack-widening TS2345 in any consumer).
- 4 vitest suites + G1 sentinel — 33 tests passing (12 new goAdapter tests +
  21 regression-free across the existing suite).

Prior-art: prior-art-evaluations.md#197 (cargo cargoAdapter ADAPT — the
closest precedent; go module path is the identity, not Cargo.toml [package],
but the adapter seam + readInstalledMeta synthesis shape transfer directly).
…rity (J3)

The fourth EcosystemAdapter (go) wires into the install.sh delivery surface:
- packages/core/templates/go/.golangci.yml — forbidigo ban on os.Getenv (the
  go analogue of clippy.toml's std::env::var disallow; F7 cell grammar).
- packages/core/templates/go/github-actions-ci.yml — exact-pinned go-version
  (1.22.0) + golangci-lint (v1.55.2) per ci-tool-pinning.md Rule A — the
  F10 two-surface pin-parity consumer mirror.
- setup.d/47-go.sh — the go lane: fresh / idempotent-if-getff / REFUSE
  collision cells, F8 firing self-check with loud-degrade (§1.3
  «insufficient (tool absent)» reporting label), D2 fingerprint ladder
  (sha256→shasum→md5/md5sum, algorithm-prefixed), D3 rules-lock.go.json
  with F11 core fields + per-lane extras. INERT-ON-NPM contract.
- install.sh — do_go_lane() mirrors do_cargo_lane; go-lane detection
  (explicit positional wins; --refresh marker; fresh auto-detect when
  go.mod present + no package.json/pyproject.toml/Cargo.toml → OFFER).
- tests/install-sh/rules-lock-schema-parity.test.sh — adds go arm (2b):
  scratch install → F11 core set ⊆ emitted keys.
- tests/install-sh/snapshot.sh — adds go/greenfield + go/brownfield-golangci
  baselines; go lane excluded (.getff-go-install.log + rules-lock.go.json
  both carry wall-clock timestamps).
- tests/install-sh/baselines/go/* — captured greenfield (3 files) +
  brownfield-golangci (4 files: REFUSE cell) fingerprints.

Prior-art: prior-art-evaluations.md#197 (cargo EcosystemAdapter, verdict
REFERENCE — the go adapter mirrors its seam shape; the lane shape is the
existing python/cargo pattern extended to a fourth family, not a new
capability per the F5 idiom). Escape hatch: the lane IS a new
data-shaped surface (setup.d/47-go.sh + packages/core/templates/go/), but
its capability-class is EcosystemAdapter-wiring + delivery-lane-mirror,
both already in the SSOT.
…y (J3)

The go CI arm in .github/workflows/audit-self.yml mirrors the rust arm shape
(audit-self.yml:265-274), adapted for go's "golangci-lint is a SEPARATE
binary not bundled with the toolchain" divergence. Three steps:

1. Cache pinned go toolchain (key: go-toolchain-1.22.0-golangci-v1.55.2).
2. Install exact-pinned go-version + golangci-lint@v1.55.2 per
   ci-tool-pinning.md Rule A — bare `run: go install` without @<tag>
   would be a non-deterministic version resolved from main.
3. Run getff go lane live-fire: scratch fixture, `install.sh go`, then
   verify all three lane artefacts (.golangci.yml, getff-go.yml,
   rules-lock.go.json) landed + the F8 firing self-check executed
   against the pinned toolchain. The runner arm proves E1 red/green
   (kickoff §1.3: «where the E1 red/green proof actually lands» — T-EW-C
   posture: until the runner arm is green and linked, E1 is unproven).

F10 two-surface pin parity (arm P1): the framework pin strings here match
the consumer template at packages/core/templates/go/github-actions-ci.yml
exactly (go-version '1.22.0' + golangci-lint v1.55.2). A pin bump is a
deliberate edit that bumps both surfaces in lockstep.

Phase 3 park note (§1.2 E3): the go arm does NOT run a vitest include-
allowlist like MT S2's test:backends — backends/go/ structure is parked
per kickoff §1.2 (E3 unsettled). The arm proves E1 via the lane firing
self-check (F8) on the runner instead.

Prior-art: prior-art-evaluations.md#197 (cargo EcosystemAdapter,
REFERENCE) — the CI arm shape mirrors the rust arm at audit-self.yml:250-274;
no new capability introduced.
…eal, prove firing, drop F3 partial bypass (J3)

Pre-egress cold fidelity audit (agents/fidelity-auditor.md) on the container
diff returned FIDELITY: REVISE with two MAJOR + three MINOR findings. All
addressed here; no PR was opened and nothing was pushed before this commit.

MAJOR 1 — go toolchain is now PINNED, not just printed.
.github/workflows/audit-self.yml go arm: replaced the bare `go version` print
with actions/setup-go@41dfa10 # v5.4.0
carrying go-version: '1.22.0' — the same pin surface the consumer template
uses (packages/core/templates/go/github-actions-ci.yml). F10 two-surface
parity is now real: both surfaces carry a pin string that must move in
lockstep. golangci-lint@v1.55.2 was already correctly pinned; left alone.

MAJOR 2 — live-fire arm now proves FIRING, not just DELIVERY.
The lane's _go_firing_self_check (F8) returns rc=0 on every branch by
contract (setup.d/47-go.sh:296), so artefact-existence alone cannot discharge
arm E1. Step now captures the install.sh output, greps for the lane's OWN
failure markers (SILENT / OVER-BROAD / NOT proven (tool absent) / ✗), and
asserts the positive «enforcement is live» summary line is present. Keeps
the existence checks; they are necessary, just not sufficient.

MINOR 3 — partial F3 bypass removed from ecosystem-go.ts.
The adapter's `readInstalledMeta` previously returned null for a single-label
first segment (`internal/foo`, `example`). That single-label rejection is one
of the stages frozen INSIDE tier1For (allowlist-resolver.ts:243 —
`if (!host.includes('.')) continue;`). Returning null here bypassed it
partially. The adapter now hands the synthesized URL through unconditionally
and lets tier1For reject; only the NAME-surface `isUnsafeDepName` guard
remains (F6 legitimately adapter-local). The paired test
ecosystem-go.test.ts:150-178 now asserts pass-through (returns synthesized
URLs), with a sanity check that the synthesized hostname has no dot so
tier1For's reject stage WILL fire downstream.

MINOR 4 — code comment in audit-self.yml is now an explicit PARK.
The «E3 PARKED — see PR body §5 «E3 park» for Option A vs Option B with
consequences» comment defers to the PR body where the park is restated in
the reviewer-requested format. Reviewer said «leave the code as is» — no
backends/go/ ships, and the park travels via the PR body.

MINOR 5 — GITHUB_PATH same-step ineffective under set -euo pipefail.
The install step echoes $GOPATH/bin to $GITHUB_PATH (effective on subsequent
steps only), so a same-step `golangci-lint --version` would die if the dir
wasn't already on PATH. Fixed by invoking golangci-lint by absolute path
"$(go env GOPATH)/bin/golangci-lint" --version inside the install step; the
next step finds it on PATH via setup-go's $GITHUB_PATH contribution.

Tests:
- npx vitest run packages/core/research/ecosystem-go.test.ts → 12/12 pass
- npx vitest run packages/core/research/ecosystem-{name,adapter-precondition,registry,unwired-debt}.test.ts → 30/30 pass
- npx vitest run packages/core/principles/{09-doc-authority-hierarchy,11-build-first-reuse-default}.test.ts → 21/21 pass
- SNAPSHOT_MODE=compare bash tests/install-sh/snapshot.sh → 15/15 byte-identical
- bash tests/install-sh/rules-lock-schema-parity.test.sh → 9/9 pass

Prior-art: skipped — refactor of existing surfaces only (CI arm + adapter
under test), no new capability.
…(J3)

The go: prefix test was added to the working tree during the pre-egress
review round (the §4.1 A1 false-citation finding) but never committed.
The PR body at .ai-factory/plans/adapter-jig-j3.PR-body.md:58 cites this
test as the evidence for §4.1 A1, so an uncommitted file would re-create
the exact defect the prior review round made us fix — only worse, because
the citation would look correct in the body while the test was absent
from the diff. Committing as a new commit on top of e262e77 (no squash,
no force-push) per git-conflict-merge-forward.md §3.
@artyhoo
artyhoo enabled auto-merge (squash) August 1, 2026 17:55
Test added 2 commits August 1, 2026 20:56
…nity loop (J3 CI red)

Orchestrator-applied Tier-0 fix post-harvest, disclosed rather than silent:
the worker task is closed, and re-opening an aif rework round for a one-token
type fix would burn quota the operator has paused to conserve.

`InstalledMeta.homepage` is optional; the MINOR-3 rework's sanity loop passed
`m!.homepage` (string | undefined) to `new URL(...)` — TS2345 under strict,
the sole real failure in the PR #1171 rollup (the principles job's 3s fail is
this typecheck cascading; principles pass 341/341 locally at this SHA).
Runtime was never at risk: the three preceding expects prove homepage is set.

Verified: tsc --noEmit clean; ecosystem-go.test.ts 12/12.

Prior-art: skipped — one-token type assertion in an existing test file; no capability, no dependency, no code module.
…x change (J3)

The worker's resolve-ctx.ts wiring (+2 lines, arm G2) feeds synth-and-wire.ts,
but the committed bundle was not regenerated — the pre-push synth-bundle drift
gate blocks the branch (CI never reached its own copy of this check because
typecheck failed first). Regenerated via the gate's own prescription:
scripts/build-synth-bundle.sh; no hand edits.

Prior-art: skipped — generated-artifact regeneration only, no capability and no source change.
artyhoo added a commit that referenced this pull request Aug 1, 2026
…tion B backends/golangci/ (#1214)

Dispatch kickoff for the autonomous aif-handoff task that closes PR #1171's 3
remaining RED-CI failures (B1 setup-go bogus SHA 41dfa10→0aaccfd150, fidelity
Round 2, ci-success) AND ships the Option-B backends/golangci/ E3 parity
structure (operator decision 2026-08-01, chosen over lane-only Option A for
structural parity with all 4 existing backends npm/ruff/astgrep/cargo).

Authored under double cold review (operator instruction «двойное и очень
тщательное»): round 1 found BLOCKER (branch-strategy self-contradiction) + 5
MAJOR; all resolved in round 2 (BLOCKER→RESOLVED, anti-fabrication gate
closed via status:"no"+refusedCode:PENDING-RUNNER-CAPTURE design, host-verify
job-level E1 check). No STOP/BLOCKER remains.

Tier 1 — §2.1 design judgment (go Tier-1 host-derivation + E3 capability-matrix
shape) carried by executor; cold-review owned by dispatching session.

Co-authored-by: Test <test@example.com>
Test added 6 commits August 6, 2026 12:21
…l v5.4.0

Both `uses: actions/setup-go@...` sites pinned
41dfa10bad2d2ebc6f5a188428eb60db4a9232c5, annotated `# v5.4.0`. That commit does
not exist: `gh api repos/actions/setup-go/commits/<sha>` returns HTTP 422 "No
commit found for SHA". The CI job failed at runner setup with "Unable to resolve
action actions/setup-go@41dfa10... unable to find version".

Failure shape: the value shares the 11-char prefix `41dfa10bad2` with the REAL
v5.1.0 tag (41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed) — a real prefix with a
confabulated tail, then annotated with a version (v5.4.0) that does not even
match the prefix it borrowed.

Replaced with the real v5.4.0 commit 0aaccfd150d50ccaeb58ebd88d36e91967a5f35b
(`gh api repos/actions/setup-go/tags`), preserving the author's stated intent.
Swept every pinned action SHA on this branch (14 total) against the GitHub API —
all resolve after this fix.

Note: nothing in the repo verifies that a pinned SHA resolves, so this reached
CI, the last-resort gate, in violation of the earliest-reachable-channel
invariant. A pre-push arm for ci-tool-pinning.md is filed separately.

Prior-art: skipped — bug fix replacing an unresolvable pinned SHA with the real
upstream commit; no new capability, dependency, or module introduced.
…ency tree

The committed bundle failed `scripts/build-synth-bundle.sh --check` for every PR
that touched this tree, including #1175 and #1171 — the drift was inherited from
staging, not introduced by either branch.

Root cause: the committed bundle was produced on an OUT-OF-LOCK node_modules. It
inlines a `semver` build containing `isPrereleaseIdentifier`, a symbol absent from
the version package-lock.json pins (root `semver` => 7.7.4; `grep -rl
isPrereleaseIdentifier node_modules/semver/` finds nothing). A rebuild from the
locked tree therefore differs from the committed artefact in 44 diff lines, all
inside the inlined semver prerelease-comparison code — the entry `.ts` source is
byte-identical between staging and this branch, so no source change is involved.

Rebuilt from the locked tree so the artefact matches what CI produces after a
lockfile install. Both drift gates verified locally:
  scripts/build-synth-bundle.sh --check        → in sync
  scripts/build-shipped-eslint-rules.sh --check → 24 checks in sync

Regenerating a conflicted generated artefact during merge-forward is the
documented step in .claude/rules/git-conflict-merge-forward.md.

Prior-art: skipped — regeneration of a generated bundle to match the lockfile; no
new capability, dependency, or module introduced.
My earlier rebuild on this branch (be4093e) was produced on a worktree whose
dependency topology did not match the destination, so it silently inlined the
WRONG semver: it dropped `isPrereleaseIdentifier`, a symbol staging's artefact
carries (2 occurrences) and CI's build expects.

Root cause, verified rather than inferred:
  - `packages/core/package-lock.json` pins semver 7.8.1; CI installs exactly that
    with `npm ci --prefix packages/core` (.github/workflows/audit-self.yml:212).
  - The ROOT lock pins 7.7.4. A worktree whose `packages/core/node_modules` is not
    the main checkout's tree resolves the root copy, and the two produce different
    bundles from identical sources.
  - Decisive check: building in the MAIN checkout reproduces staging's committed
    bundle byte-for-byte; building in an under-provisioned worktree does not.
    CONTRIBUTING.md:20 already requires symlinking BOTH node_modules — that
    requirement is what this violated.

This rebuild was produced after `scripts/worktree-node-modules.sh` restored the
topology. It now differs from staging's artefact by exactly one line — this
branch's own `go` entry in KNOWN_ECOSYSTEM_PREFIXES — which is what a correct
deterministic build should yield, and it retains `isPrereleaseIdentifier`.

Verified on the host: `NODE_ENV=development bash scripts/build-synth-bundle.sh
--check` → in sync.

Prior-art: skipped — regeneration of a generated bundle on a correctly-provisioned
tree; no new capability, dependency, or module introduced.
…on failure

CI run 31093381580 reported «1 ok · 0 SILENT · 1 OVER-BROAD» — the delivered config
fired on the clean control — and the log carried nothing to root-cause it with. The
self-check captured both runs into `_out` / `_out_clean` and printed neither on the
✗ branch (setup.d/47-go.sh:259-277 before this commit), so the only diagnosis channel
left was «install go + golangci-lint v1.55.2 and re-run by hand». A verdict that
cannot be acted on from the log is not a mechanism
(.claude/rules/attention-is-not-a-mechanism.md §1).

This commit changes reporting only — no verdict logic, no delivered artefact:

  - `_go_dump_lint_output` prints the failing run verbatim (exit code + indented
    output, or «(no output)») on BOTH failure directions, SILENT and OVER-BROAD.
  - the OVER-BROAD branch additionally lists the .go files present in the temp
    module at clean-control time. That discriminates the two failure classes the
    exit code alone cannot: a genuinely over-broad pattern (fires on clean.go) vs.
    a leftover violation.go the `rm -f` did not remove.

Delivered files are untouched, so the go baselines (which hash delivered artefacts,
not installer stdout) do not move: tests/install-sh/baselines/go/greenfield.fingerprint
lists .github/workflows/getff-go.yml, .golangci.yml, go.mod only.

Verified: `bash -n setup.d/47-go.sh` exit 0; `shellcheck -x setup.d/47-go.sh` reports
the same single pre-existing SC2317 info at the file's trailing `return 0` and nothing
new (confirmed against the pre-edit file); helper rendering smoke-tested standalone on
both the populated and empty output cases.

Prior-art: skipped — adds diagnostic output to an existing self-check in one shell
function; no new capability, dependency, or module introduced.
…regex banned everything

The shipped .golangci.yml declared the ban as `- pattern: 'os\.Getenv\('`. forbidigo's own
struct tags that field `Pattern string \`yaml:"p"\``, and golangci-lint v1.x — the pin this
lane installs, v1.55.2 — vendors that struct as-is; only the v2 config schema renamed the key
to `pattern`. Under v1.55.2 `pattern:` is an unknown key, silently dropped, leaving the regex
EMPTY. An empty regex matches every identifier, so the delivered config banned all Go code
while still printing our msg (msg IS a real key, which is why the diagnostic looked plausible).

Evidence — CI run 31109093736, clean-control run, three findings in a file containing no
violation at all:

    selfcheck/clean.go:1:9:  use of `selfcheck` forbidden because "Read configuration ..."
    selfcheck/clean.go:5:15: use of `string`    forbidden because "Read configuration ..."
    selfcheck/clean.go:6:9:  use of `os.Args`   forbidden because "Read configuration ..."

Key name verified against forbidigo's source rather than inferred from the symptom
(ashanbrown/forbidigo, `type pattern struct` — `Pattern string \`yaml:"p"\``, `Package` →
`pkg`, `Msg` → `msg`).

The trailing `\(` also goes. forbidigo matches a node's source text — `os.Getenv("HOME")` in
literal mode, the bare `os.Getenv` once type analysis expands it — so the paren-free form
matches in both modes and survives a future `analyze-types: true`. `os.Args` stays unmatched
either way, which is precisely what the clean control asserts.

What this says about the check that caught it: the RED direction alone could not have found
this. An always-matching config fires on the planted violation too, so the positive arm went
green on a config that banned the language itself. Only the paired CLEAN CONTROL discriminated
— the adapter-jig E1 arm working exactly as specified.

Baselines: the delivered config's hash moves, so both go fingerprints are regenerated
(`SNAPSHOT_MODE=capture bash tests/install-sh/snapshot.sh`). Re-verified: SNAPSHOT_MODE=compare
→ 15 pass / 0 fail, the two go cells byte-identical again.

Not verified locally: this host has no go toolchain (`command -v go golangci-lint` → not
found), so the firing proof itself is the CI go arm on the pinned go 1.22.0 + golangci-lint
v1.55.2 — RED on the planted violation, GREEN on the clean control.

Prior-art: skipped — one-key bug fix in an existing delivered template plus its regenerated
baselines; no new capability, dependency, or module introduced.
artyhoo added a commit that referenced this pull request Aug 6, 2026
…staging (#1224)

## What

The J3-redfix dispatch kickoff (merged via #1214) was never dispatched, and every row of its §1 has
since closed on PR #1171: the fabricated `actions/setup-go` SHA, the `install.sh` conflict, the stale
synth bundle, and — found today — an OVER-BROAD delivered golangci config that §1 could not have known
about, because the go arm never reached the firing self-check while setup-go 404'd.

What survives is §2: the Option-B `packages/core/backends/golangci/` E3 parity structure the operator
chose on 2026-08-01. This PR carries it forward as its own kickoff, re-baselined onto current staging.

## Why the branch strategy inverted

The old kickoff had aif push straight to PR #1171's branch. That branch's own scope is finished and
green; it already went CONFLICTING once when staging moved 34 commits ahead, and it is 10 behind again
hours later. Option B is additive — one new directory plus its tests, touching no lane artefact — so it
ships as its own PR and #1171 merges independently. That also unties the old §1 B2 sequencing knot,
where the fidelity verdict had to wait on an in-PR cell upgrade.

## Changes

- New `.claude/orchestrator-prompts/adapter-jig-j3-option-b/kickoff.md` (273 lines): §2 carried forward,
  fresh branch strategy, a STOP line forbidding any push to `feature/adapter-jig-j3-d4db43` or edit under
  `setup.d/` / `templates/go/` / `.github/workflows/`, and a Tier-1 `bridge-profile` marker
  (`Z.AI GLM-5.2 SDK`, verified unique against the live `/runtime-profiles` list).
- New domain trap **T-AJ-D — «v2 documentation against a v1 pin»**, the generalisation of today's defect:
  the config declared `pattern:` (the golangci-lint v2 key) under a v1.55.2 pin, leaving an empty regex
  that banned every identifier.
- Header pointer on the superseded kickoff so no future session dispatches it.

## Verification

- `bash scripts/host-verify.sh --list adapter-jig-j3-option-b` → exit 0, 4 commands extracted
- `.claude/hooks/check-kickoff-traps.sh` on the new kickoff → exit 0 (8 distinct T-numbers + 3 domain traps)
- markdownlint → 0 errors; both files under the 600-line gate (273 and 382)

## Fidelity verdict

FIDELITY: skipped — prose-only dispatch-input re-scope; no kickoff governs the authoring of a kickoff, and the deliverable it describes is not built here

## Parked questions

n/a

## §1.7 Self-discipline check

### §1.7 Skipped: dispatch-input maintenance — re-scopes an existing kickoff onto current staging and adds a supersession pointer; introduces no discipline rule
Test added 2 commits August 7, 2026 00:07
…irror was guarded by a comment (J3)

Fidelity audit round 2 (agents/fidelity-auditor.md, cold, over 64caa85) returned REVISE on
one MAJOR: kickoff §2 deliverable 4 names arm P1 / F10 two-surface pin parity, and the round-1
fix created the second pinned surface without registering the pair.

go was pinned on BOTH surfaces — framework .github/workflows/audit-self.yml:292,306 and consumer
packages/core/templates/go/github-actions-ci.yml:48,53 plus setup.d/47-go.sh:147,306 — while the
arm's own test still scanned ast-grep + ruff against setup.d/45-python.sh only
(packages/core/hooks/pin-parity.test.ts:34,47-53). The only thing keeping the two go pins in
step was the prose at setup.d/47-go.sh:143, "Keep the two in sync on any pin bump" — which is
the #warning-nobody-reads shape from .claude/rules/attention-is-not-a-mechanism.md §2, i.e. the
exact defect class arm P1 exists to replace. The per-line unpinned gate cannot see it either:
both lines ARE pinned, just potentially to different versions.

The consumer surface is now per-tool (`TrackedTool.consumerSurfaces`) rather than one global
constant, because each lane delivers through its own files — the go family is what forced it.
Two go tools join the population: `go-toolchain` (the quoted `go-version:` setup-go input,
mirrored on the delivered CI template) and `golangci-lint` (the `@v`-tagged go install, mirrored
on the CI template AND the lane's REFUSE-path hint, which restates the pin as text a consumer is
told to run). The lane's `go 1.22` at setup.d/47-go.sh:268 is a go.mod language directive in a
scratch fixture, not a toolchain pin, and is deliberately not a mirror partner.

checkPinParity now takes its tool list explicitly: with a per-tool consumer half, scanning a
surface for a tool it never delivers would report a phantom missing-pin. The existing synthetic
negatives pass the python subset; a new go-shaped negative proves both go pin FORMS are really
parsed (quoted `go-version:` input, `@v`-tagged install), not merely declared.

Verified the arm actually fires rather than merely passing: mutating the delivered template's
go-version 1.22.0 -> 1.23.0 turns the REAL-tree test RED with
"go-toolchain: pin divergence — framework pins {1.22.0}, consumer pins {1.23.0}"; reverted, 7/7
green. tsc --noEmit clean; 33 tests across pin-parity + ecosystem-go + unwired-debt +
ecosystem-name green; actionlint clean; synth bundle in sync (--check).

Also from the same audit, three MINORs:

- The go binary was never actually cached. The cache path listed `${{ env.GOBIN }}`, but GOBIN is
  unset workflow-wide, so that entry expanded to empty while `go install` wrote to
  $(go env GOPATH)/bin — the very path the next step invokes absolutely
  (.github/workflows/audit-self.yml:311). Now `~/go/bin`. Module and build caches were unaffected,
  so this was slower, not wrong.
- packages/core/research/ecosystem-go.test.ts:3 cited .ai-factory/plans/feature-adapter-jig-j3-d4db43.md,
  a path that exists nowhere on this branch. Repointed at the binding kickoff.
- packages/core/synthesizer/resolve-ctx.ts:37-41 still enumerated only python/cargo/npm while :61
  already selected goAdapter. Doc comment now matches the code it documents.

Prior-art: skipped — arm-population extension plus three comment/config corrections on an existing
capability; no new dependency, module, or problem-class introduced.
… it describes (J3)

Fidelity round 3 (GO) left one MINOR, introduced by round 2's own widening: the registry — which
the kickoff §0/§1.2 names as the canonical arm list — still enumerated P1's population as
"ast-grep + ruff", while hooks/pin-parity.test.ts now tracks four tools. A registry that names a
narrower population than the arm enforces re-teaches the next stamped family the old, smaller
scope, which is the failure the canonical list exists to prevent.

Comment-only; the registry's load-bearing data (suite + locator rows) is untouched. tsc clean;
31 tests across the arm-registry meta-check + pin-parity green.

Prior-art: skipped — comment correction keeping a canonical enumeration in step with the code it
describes; no capability, dependency, or module introduced.
@artyhoo
artyhoo merged commit 124d2c4 into staging Aug 6, 2026
2 checks passed
artyhoo added a commit that referenced this pull request Aug 6, 2026
…ope (#1235)

Two dispatch inputs for the same umbrella, both gated on state that only just became true.

**S3 (new)** — one beat + per-stack research paths, spec §6. Its gate (S2b merged, #1233
`a66c0cb9aa`) cleared minutes ago, so this is the first moment S3 could be planned against a
tree that exists. Anchors re-verified live at `a66c0cb9aa`, not carried from the spec:
`agents/rule-researcher.md` has 0 hits for python/pyproject/ruff (wall #4 confirmed);
`INSTALL-FOR-AI.md` has 0 hits for the continuation clause; the delivered starter AGENTS.md
comes from `packages/core/templates/shared/AGENTS.md.template` via `setup.d/45-python.sh:808`;
`_py_join_researched_rules` is at `setup.d/45-python.sh:161`; the F-A bundling precedent
`synth-and-wire.bundle.mjs` is 395 149 bytes as committed.

S3 owns fork F-A (Node for the generation CLI: bundle vs declare honestly) — spec §12 assigns
it to «the trace umbrella's planner» and gives size-and-maintenance-cost criteria, so the
kickoff instructs RESOLVE-with-measurement, not park, and hands it a real maintenance datapoint:
the 2026-08-07 S2b egress hit a synth-bundle drift caused by root-vs-packages/core lock
disagreement on semver (7.7.4 / 7.8.1 / 7.8.5).

Scope note carried explicitly: `setup.d/47-go.sh` + `do_go_lane()` landed 2026-08-06 (#1171).
S3 stays python + a rust pointer per spec §6.2 and is told not to widen to go, but also not to
let the researcher-agent edit read as lane-complete while omitting it.

**R1 §8 (amendment)** — round-2 rework scope after a `FIDELITY: STOP` at the egress seam.
Round 1's patch is on `research/getff-any-stack-trace-r1` (`1479f54741`) with no PR opened.

The BLOCKER is a false negative-existence claim about the go lane — and the amendment records
that this was NOT worker error. Verified mechanically rather than inferred:

    git show 0e2d366:install.sh | grep -cE 'do_go_lane|TOOLCHAIN=go'    -> 0  (R1's base)
    git show origin/staging:install.sh | grep -cE 'do_go_lane|TOOLCHAIN=go' -> 6  (today)
    PR #1171 merged 2026-08-06T22:04Z

R1's search was honest and correct when it ran on 2026-08-01; the go lane landed five days
later, fifty minutes before the egress. The audit aged out. Round 2 must verdict all 7 go cells
against the live tree AND record the staleness itself as a finding — a parity audit's verdicts
are only as live as the tree they were taken against.

Three MAJORs in the same amendment are NOT staleness and stand on their own against §2/§3 as
originally written: npm rung 6 is the only EXISTS with no firing evidence (plus four line
anchors that no longer resolve); five further EXISTS cells rest on analogy («same machinery
as…») rather than a cited firing artefact; and a hybrid `EXISTS*` token breaks «exactly three
verdicts», leaving the §7 GAP counts unreconcilable with the matrix.

New round-2 trap T-R1-D — patching the auditor's findings instead of re-deriving them: the
line numbers in §8 are a map, not evidence, and a round-2 patch citing them second-hand would
launder exactly the failure class it exists to fix.

Both kickoffs validated locally: principle 12 (traps enumeration) 7/7; `host-verify.sh --list`
resolves S3's three-command contract and accepts R1's 161-char prose-only opt-out.

Prior-art: skipped — dispatch-input authoring only; no capability, no dependency, no code module.

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 6, 2026
…ig J3 Option B) (#1236)

* feat(backends/golangci): scaffolding + fixtures

adapter-jig J3 Option B — structural mirror of the four existing backends
(npm/ruff/astgrep/cargo) for golangci-lint. Ships the golangci-forbidigo
backend scaffolding so the E3 arm (committed firing evidence records the
producing tool version; a freshness gate REDs on drift) holds for go too.

Artefacts (kickoff §2 steps 1-4 + §4c fork-don't-guess):
- capability-matrix.json: parked syntax cell (status:"no" +
  refusedCode:"PENDING-RUNNER-CAPTURE"); type-aware + dep-graph refused
  FF7001. validateMatrix accepts (a "no" cell requires no evidence).
- firing-contract.json: FORK #2 PARKED — command (stable across v1.x)
  honest; jsonPath + expectedCodes empty + parkReason. Dispatching session
  fills from a captured v1.55.2 run at host-verify §6 step 7 (T-AJ-D).
- firing-runner.ts: 4 exports (parseCodesFromStdout, fireContract,
  parseGolangciVersion, deriveGolangciVersion) — no checkToolchainFreshness
  (that lives in capability-matrix.test.ts per the four-precedent shape).
  Uses the shared JSON-array parser (ruff precedent; golangci-lint emits a
  JSON array, not cargo's NDJSON).
- fixtures/firing/{invalid,valid,valid-clean}/: three minimal go modules.
  invalid fires os.Getenv("HOME"); valid uses an injected accessor (no
  //permit: directive — fork #3 resolved conservatively per kickoff §2
  step 6); valid-clean is trivially conforming. Each carries the canonical
  .golangci.yml ban literal (forbidigo, one pattern 'os\.Getenv' under
  yaml key `p` — NOT `pattern`: forbidigo v1.x vendors the struct tag
  yaml:"p"; `pattern:` is silently dropped under v1.55.2, leaving an empty
  regex matching every identifier — T-AJ-D).

Predecessor (lane PR #1171, ships the go lane itself) is independent of
this branch; this PR is purely additive (packages/core/backends/golangci/
only, zero edits under setup.d/, packages/core/templates/go/,
.github/workflows/, packages/core/ir/, or frozen rows F1-F11).

Prior-art: prior-art-evaluations.md#226 (structural mirror of the four existing backends; verdict ADOPT — same problem-class, same shape).

* test(backends/golangci): capability-matrix + firing paired-negatives

adapter-jig J3 Option B — the always-on paired-negative suite for the
golangci backend (kickoff §2 steps 4-5 + §3 acceptance, T2/T20).

capability-matrix.test.ts (4 describe blocks):
- validateMatrix paired-negatives (5 tests): partial-without-evidence is
  a violation; "no" cell is clean (anchors the parked syntax cell); caps
  on a "no" cell is a violation; partial-with-valid-evidence is clean;
  mismatched identity is a violation. Identity extractor
  (extractFromLinter -> parsed.FromLinter) is the v1.x working hypothesis
  flagged PROVISIONAL pending §6 step 7 capture (T-AJ-D); no committed
  cell exercises it at worker-done time.
- parseGolangciVersion + checkToolchainFreshness paired-negatives
  (7 tests, always-on, pure): semver extraction (v-prefix AND bare),
  undefined on non-golangci string, fresh==resolved clean, stale!=resolved
  RED-capable (THE E3 negative the §3 acceptance quotes), non-golangci
  toolchain string → "does not name a golangci-lint version" violation,
  "no" cell contributes no freshness violation.
- committed capability-matrix.json passes validateMatrix: empty
  expectedIdentity harmless (no non-"no" cells at worker-done time).
- structural honesty: syntax.refusedCode === "PENDING-RUNNER-CAPTURE",
  syntax.evidence undefined, type-aware + dep-graph refused FF7001 —
  locks the worker-done state so the §6 step 7 upgrade is a visible diff.
- toolchain freshness loud-skip when golangci-lint absent (NO !isCI guard
  — ruff/firing.test.ts:14-16 STOP-line; CI fires for real when the lane
  audit-self.yml install step is present).

firing.test.ts (2 describe blocks):
- live golangci-lint check (describe.skipIf !toolPresent): RED + 2 GREEN
  tests. At worker-done time all three SKIP loudly (golangci-lint absent
  in aif container) — honest outcome, NOT a "green from a run that didn't
  fire" (T-AJ-A). The §6 step 7 runner capture fires them for real.
- self-application drift block (always-on, PURE): each fixture's
  .golangci.yml == canonical ban literal (byte-for-byte). No render call
  (kickoff §5 STOP-line — render-golangci.ts not built).

In-container verify: 17 passed | 4 skipped (live-fire + toolchain-freshness
gates on golangci-lint absence — loud, never silent).

Prior-art: prior-art-evaluations.md#226 (paired-negative shape mirrored from cargo/ruff; verdict ADOPT).

* fix(backends/golangci): parseGolangciVersion must match the REAL --version output

Cold fidelity audit (round 1) graded this MAJOR before merge: the shipped regex
required the semver ADJACENT to the tool name, but the v1.x binary prints
`golangci-lint has version 1.55.2 built with go1.21.4 from <sha> on <date>`.

Source-verified, not inferred: golangci/golangci-lint `BuildInfo.String()` formats
"golangci-lint has version %s built with %s from %s on %s", and BOTH `--version`
and the `version` subcommand print through it.

Why it mattered. `deriveGolangciVersion()` would have returned undefined on a
machine that HAS golangci-lint installed — indistinguishable from "tool absent".
The freshness gate would loud-skip forever and CI would stay green while the E3
arm never fired. This branch rebases onto staging, which already carries the go
arm's pinned install (`golangci-lint@v1.55.2`, audit-self.yml:306-312, PR #1171
as 124d2c4), so the defect was certain to bite in CI, not merely possible.

RED before GREEN, measured:
  old regex on the real output -> undefined   (the inert-gate shape)
  new regex on the real output -> 1.55.2
  new regex still rejects `ruff 0.15.21` -> undefined
  new regex on `... has version 1.54.0 ...` -> 1.54.0 (drift still discriminates)

Changes:
- widen the regex by exactly one optional group, `(?:has\s+version\s+)?`; the two
  previously-accepted shapes keep working.
- add the missing test case carrying the real `has version` output — without it the
  suite was green against a string the binary never emits (T-AJ-A: the arm passes
  because it tests the fixture, not the lane).
- three prose corrections the same audit raised: drop a past-tense "Verified live"
  claim for a verification that has not happened; correct the kickoff path in three
  file headers; correct two comments asserting the audit-self install step is "NOT
  present on this branch yet" — it is present on this branch's base.

Prior-art: skipped — repairs an in-branch defect in a capability already cited as prior-art-evaluations.md#226 in this PR's two preceding commits; introduces no new capability area.

* fix(backends/golangci): cite the --version format at the PIN, and test the shape CI really emits

Round-2 cold fidelity returned GO with one MINOR, and the MINOR is the same trap the
previous commit was fixing — T-AJ-D, a golangci fact read off master instead of the
pinned v1.55.2. Fixing it rather than shipping a knowingly-wrong citation.

1. Symbol attribution corrected. At tag v1.55.2 the format string lives in
   `printVersion()` in `pkg/commands/version.go`; `BuildInfo` there is a plain struct
   with NO `String()` method — the format only moved onto `BuildInfo.String()` in a
   later release. The BEHAVIOURAL claim was right (verified verbatim at the tag) and
   nothing executable depended on the symbol name, but a comment that exists to justify
   the regex must survive a reader looking the symbol up at the pin.

2. Three test cases added, all covering paths the previous commit left unasserted:
   - the shape CI ACTUALLY produces. The go arm installs via `go install …@v1.55.2`
     with no goreleaser ldflags, so the version falls back to `buildInfo.Main.Version` —
     the tag string WITH its leading `v` — and the date renders "(unknown)". So the real
     CI line carries the `has version` prefix AND a `v` prefix at once. Two separately
     tested groups are not evidence that they compose; now it is asserted directly.
   - a foreign tool that also prints "has version" is still rejected
     (`staticcheck has version 1.55.2 …` -> undefined), so the widening did not turn the
     matcher into "any tool, any version".
   - a DRIFTED version read out of the real shape (1.54.0), so drift detection is proven
     against the real format, not only the evidence-string format.

3. Two comments cited the audit-self install step as lines 306-312; the step runs to 315.

Prior-art: skipped — comment attribution + three test cases on an in-branch capability already cited as prior-art-evaluations.md#226; no new capability area.

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 7, 2026
…s J3 Option-B stage (#1243)

## Summary

Umbrella closure bookkeeping. [#1240](#1240) closed the last item owed by adapter-jig J3 Option B (§6 step 7 evidence capture + W-7), so per the umbrella closure convention the merging session writes `done.md`. With J1 (#1087), J2 (#1094) and J3 (#1171) all merged, the parent `adapter-jig` umbrella is complete as well.

## Changes

- `.claude/orchestrator-prompts/adapter-jig/done.md` — parent umbrella, final PR #1240
- `.claude/orchestrator-prompts/adapter-jig-j3-option-b/done.md` — the J3 Option-B stage umbrella, final PR #1240

Both feed `priority-score.sh` completion Layer C3, which short-circuits the expensive C2 jaccard pass per umbrella ([priority-score.sh:140](../blob/staging/.claude/skills/pipeline/helpers/priority-score.sh#L140)); without them these two dirs keep scoring as open candidates.

**Not written here, surfaced instead:** `adapter-jig-j3/` and `adapter-jig-j3-redfix-meta-launch/` are also complete and also lack `done.md`. Backfilling them is a separate concern from this session's closure obligation and was not done autonomously (CLAUDE.md «PR strategy»). There is precedent for a batched backfill (`umbrella-donemd-backfill`).

## Prior-art consult

- [x] Capability commits in this PR carry a `Prior-art:` trailer (or `skipped — <≥20 chars rationale>` for hook-flagged commits that aren't real capability additions).
- [x] No new capability area surfaced — n/a
- [x] No existing SSOT entries matched or touched — n/a
- [x] context7 queries — n/a, no capability area

Prior-art: skipped — closure bookkeeping only: two 4-line done.md markers written per an existing convention, no code, no dependency, no capability

## Test plan

- [x] `markdownlint-cli2` green on both files (pre-commit, 0 errors)
- [x] Both files match the binding schema in operational-conventions.md §1 (`# <umbrella> — DONE` / `Final PR:` / `Closed:` / `Summary:`)
- [x] Stage PRs verified merged before claiming closure: #1087 (J1), #1094 (J2), #1171 (J3), #1236 (Option-B backend), #1240 (step 7)

## Provenance

n/a — not a stage PR.

## Review findings

n/a — not a stage PR.

## Fidelity verdict

FIDELITY: skipped — closure bookkeeping with no kickoff to audit against; two done.md markers written per an existing convention, nothing dispatched to a worker

## Parked questions

n/a

## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files)

### §1.7 Skipped: adds two done.md marker files under .claude/orchestrator-prompts/ per an existing convention; introduces and extends no rule, principle, plan, SSOT entry or shipped template
artyhoo added a commit that referenced this pull request Aug 7, 2026
…J3 family (#1246)

## Summary

Completes the closure bookkeeping started in [#1243](#1243). Two dirs in the adapter-jig family are provably finished but still lack `done.md`, so they keep scoring as open candidates in `priority-score.sh` completion Layer C3 and keep paying the expensive C2 jaccard pass ([priority-score.sh:140](../blob/staging/.claude/skills/pipeline/helpers/priority-score.sh#L140)).

## Changes

- `.claude/orchestrator-prompts/adapter-jig-j3/done.md` — the J3 stage, landed as #1171 (verified MERGED). Its E3 parity residue ran as its own umbrella, `adapter-jig-j3-option-b`, closed by #1240.
- `.claude/orchestrator-prompts/adapter-jig-j3-redfix-meta-launch/done.md` — never dispatched. Its `kickoff.md` carries an in-file `**SUPERSEDED 2026-08-06 — do NOT dispatch this file.**` banner: §1 (RED-CI fix + `install.sh` conflict) was already closed on #1171, and the surviving §2 Option-B scope was re-baselined into `adapter-jig-j3-option-b`. Final PR recorded as #1240, the PR that closed that re-baselined scope.

**Deliberately NOT written here:** `adapter-jig-meta-launch` also lacks `done.md`, but unlike these two it carries `RESUME.md` + `state.md` — a resumable runtime state. Declaring it closed is a judgment about another session's in-flight artefact, not bookkeeping, so it is left to its owner and surfaced instead.

## Prior-art consult

- [x] Capability commits in this PR carry a `Prior-art:` trailer (or `skipped — <≥20 chars rationale>` for hook-flagged commits that aren't real capability additions).
- [x] No new capability area surfaced — n/a
- [x] No existing SSOT entries matched or touched — n/a
- [x] context7 queries — n/a, no capability area

Prior-art: skipped — closure bookkeeping only: two 4-line done.md markers written per an existing convention, no code, no dependency, no capability

## Test plan

- [x] `markdownlint-cli2` green on both files (pre-commit, 0 errors)
- [x] Both files match the binding schema in operational-conventions.md §1 (`# <umbrella> — DONE` / `Final PR:` / `Closed:` / `Summary:`)
- [x] Completion verified before claiming it, not assumed: `gh pr view 1171` → MERGED, `gh pr view 1240` → MERGED, and the SUPERSEDED banner read directly out of `adapter-jig-j3-redfix-meta-launch/kickoff.md:10-18`

## Provenance

n/a — not a stage PR.

## Review findings

n/a — not a stage PR.

## Fidelity verdict

FIDELITY: skipped — closure bookkeeping with no kickoff to audit against; two done.md markers written per an existing convention, nothing dispatched to a worker

## Parked questions

`adapter-jig-meta-launch` closure — left to its owner, see Summary.

## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files)

### §1.7 Skipped: adds two done.md marker files under .claude/orchestrator-prompts/ per an existing convention; introduces and extends no rule, principle, plan, SSOT entry or shipped template
artyhoo added a commit that referenced this pull request Aug 7, 2026
…the unreleased round 1) (#1254)

* docs(getff-r1): round-2 lane × channel-rung parity audit — re-derive under §8 map

Round-1 patch was unreachable in the worker clone; round 2 re-derives every
cell against the live tree per kickoff §8 (T-R1-D). Go lane now exists
(PR #1171, 2026-08-06) and gets 7 substantive verdicts replacing round-1's
N/A absence row. §8.2 MAJORs addressed (npm rung 6 firing evidence; analogy
EXISTS cells re-derived; EXISTS* hybrid resolved). §8.3 MINORs addressed
(SSOT #216 quote literal-or-dropped; deceptive-rung findings elevated;
line-count claim replaced with section cite).

Matrix: 4 lanes × 7 rungs = 28 cells (21 EXISTS, 7 GAP, 0 N/A). Per-GAP
provenance: 1 DECIDED-AGAINST / 1 MISDECIDED / 0 DEFERRED / 5 SILENTLY-MISSED.
T7 counter-prompt run 3× (nothing surfaced). T15 self-application in §8.

Prior-art: skipped — research patch only, no new capability, no dependency, no code module

* docs(getff-r1): re-verdict python rung 2 at the egress seam — S2b closed it mid-flight

The accepting session's pre-merge re-verdict, kept as its own commit so the
auditor's round-2 output and the correction stay separable in history.

Between this audit's base (2923ba6) and staging at merge (c3cb7a6), S2b
#1233 a66c0cb landed and closes the exact cell the audit verdicted
GAP/MISDECIDED — _py_deliver_local_hook_rung at setup.d/45-python.sh:702
(header :669-701), delivering .getff/hooks/pre-push and activating it via
core.hooksPath, with a non-clobbering integration arm. Host-verified:
tests/install-sh/python-entry-lane.test.sh cases (14)-(16), PASS=80 FAIL=0.

- python rung 2: GAP -> EXISTS; provenance MISDECIDED -> RESOLVED. The §4.1
  provenance analysis is retained verbatim as the historical record of how the
  decision chain broke — that is the finding the operator asked for — with a
  status block on top.
- Tallies: 22 EXISTS / 6 GAP / 0 N/A (was 21 / 7 / 0); MISDECIDED 1 -> 0.
- Blast radius enumerated, not assumed: git diff --name-only over setup.d/,
  install.sh, packages/core/templates/ and packages/core/hooks/ across the 19
  intervening commits shows S2b's three python files as the only lane-surface
  changes. The other 27 verdicts stand at staging.
- New §6.1 records the instance itself: two rows of this audit aged out in two
  different windows — the go row in the dispatch window, python rung 2 in the
  egress window. That is the base rate for a fast trunk, so §6 gains item 4:
  re-verdict a parity-shaped patch at the egress seam, since the accepting
  session is the last channel that can catch it.

Prior-art: skipped — correction to a research patch under docs/meta-factory/research-patches/, one markdown file, no new capability, no dependency, no code module.

---------

Co-authored-by: Test <test@example.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant