provenance: record (and eventually pin) the suite SHA a run executes — skill text moved 20+ times under a live run #34
Labels
No labels
component:adapters
component:lifecycle
component:qa
component:setup
component:shared
component:worktrees
phase/accepted
phase/backlog
phase/deployed
phase/developing
phase/integrating
phase/planning
phase/qa
phase/requirements
phase/uat
priority:critical
priority:critical
priority:high
priority:high
priority:low
priority:low
priority:medium
priority:medium
type:bug
type:chore
type:docs
type:feature
type:infra
type:tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jbr870/devwork-skills#34
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
Nothing records — let alone pins — which version of the suite a run executed. The slot3/#191 deep-dive (report
verity-slot3-191-20260812.md, finding 1) established that~/.claude/skills/_sharedon the desktop is a symlink into a live git working tree that received 20+ commits, including a merge, during the run — one mid-QA commit changed the QA playbook's preconditions between stage launches. The model noticed exactly once and re-read one file. Consequences: a run's behavior cannot be attributed to any suite SHA (my own earlier attribution of the 2026-08-12 runs toae802e0was wrong); cross-slot comparison on a parallel day is confounded; and a "resolved at HEAD" verification in the process review says nothing about what text a given run actually followed.Recurrence
Mechanical/systemic — verified by construction: the symlink-farm install (README option A) makes every concurrently-running session read whatever the checkout currently holds. Every multi-session day has this property.
Hypothesis
Two independently useful halves: (1) record — Phase Outcomes gain a
suite_sha(or the PO post helper stamps it) so attribution is possible after the fact; (2) pin — a run resolves its skill text once (e.g. a per-run worktree/checkout of the suite at a SHA) so text cannot move mid-run. Recording is cheap and should come first; pinning may fall out of the plugin work (#22, cross-referenced).Suggested lane
Full pipeline (helper + schema change) for recording; #22 for pinning.
Filed by /meta-retrospective 2026-08-13 (slot3 deep-dive).
Update 2026-08-22 — UAT of #50 confirms the second half: installed-release attribution (UAT-F33)
The plugin migration (#50) reached UAT and its Phase 7 walk produced UAT-F33, which is this
issue seen from the installed side rather than the checkout side:
So the "record" half of this issue has two identity sources, and which one applies is decided
by the machine, not by the caller.
Ground truth, measured 2026-08-22 (not inferred)
Probed on both machines rather than assumed — this is the input the technical plan needs:
jochems-forge(installed plugin)$CLAUDE_PLUGIN_ROOT~/.claude/plugins/cache/devwork-skills/dev/0.1.5fatal: not a git repository; it is an extracted copy with only.claude-plugin/,skills/,.in_use.claude-plugin/plugin.json.version0.1.5— but the tree may be arbitrarily far ahead of that tag0.1.5, and the version is also literally in the install pathgit rev-parse HEAD(+ dirty flag)The two cases are cleanly separable by one probe — is
$CLAUDE_PLUGIN_ROOTinside a git worktree — so a single helper can stamp SHA-on-checkout / version-on-install without a mode flag and
without the operator declaring anything. Version alone would not have been safe (a dev checkout
ahead of the tag still reads
0.1.5); the git probe is what makes it honest.Also observed, and worth exploiting rather than duplicating: Claude Code's own
~/.claude/plugins/installed_plugins.jsonalready records both for each install —"version": "0.1.5"and"gitCommitSha": "bc6214d…". Whether to read that file (its path andmulti-scope array shape are undocumented and not ours) or stay with the
$CLAUDE_PLUGIN_ROOTprobe is a plan-time call; the probe is the portable one, that file is the corroborating one.
Separately: the desktop's marketplace snapshot at
~/.claude/plugins/marketplaces/devwork-skillsis a git clone (currently
main@bc6214d, no longer shallow after Scenario 21'sfetch --unshallow, carrying only tagsdev--v0.1.0/dev--v0.1.1). It is not the plugin root andmust not be mistaken for one — the run executes out of
cache/, not out of the snapshot.Why this is not #50's to fix — and what #50's own decisions actually said
Checked against the resolutions rather than assumed. #50 split this subject in two at plan time and
handled the halves differently:
D-PO-50-2-9andD-PO-50-2-14both resolvedaccept, on the reasoning "git is the dev machine's version identity; release attribution isdesktop-only (AC-12)". Worth noting for this issue's own framing: UAT partially undercuts that
reasoning. Git is only an identity if something records the SHA — and nothing does, which is
precisely the original observation at the top of this issue. The disposition was right that the
dev machine needs no release version; it was wrong that no recording was needed at all.
Scope bars "any skill logic change: this feature is layout + references + packaging + tooling
only", so the attribution AC-12 asked for could only be delivered as a README consumer-runbook
step telling the operator to record the version by hand. UAT-F33 is the finding that this is not
an attribution mechanism: in the one real consumer-machine run, it was not done.
So the tooling-enforced capability was never inside #50's scope on either half, and lands here.
AC-12 has been amended on #50 to claim only the manual mechanism it actually scoped, with the
enforced version pointed at this issue.
Lane
Unchanged: full pipeline (
/dev:requirements→ …). It is a helper behaviour change plus achange to a versioned contract schema (
phase-outcome:v1gains a field — whether that is abackward-compatible optional field or a
:v2is itself a plan-time question, becausephase-outcome-post.sh's retry-guard normalisation andphase-outcome-read-all.sh's parser bothread these records, and every already-posted PO lacks the field).
Adjacent defect found while confirming this (2026-08-22) — filed separately
scan_comments --header 'phase-outcome:v1'matches the token as a substring of line 1 with noshape validation, so any comment whose header merely contains it is absorbed into the Phase Outcome
ledger. A UAT closure note posted on #50 with the header
<!-- phase-outcome:v1 scenario=13 -->(no
id=, noskill=, no JSON fence) madephase-outcome-read-all.sh --issue 50die with a barejq error —
null (null) only strings can be parsed— naming no comment and no cause, and wouldhave made the next
phase-outcome-post.shmintPO-50-7, skippingPO-50-6and breaking ordinaldensity permanently. Repaired by hand (header stripped from comment 1067). Cross-referenced here
because it is the same subject: the integrity of the run record.
Live evidence from a full-pipeline run, recovered after the fact.
Feature verity #230 (in-app release notes) ran the whole pipeline —
/requirementsthrough/promoteto a verified production deploy — onae802e0(2026-08-12), 15 commits behindorigin/main. The run itself recorded nothing about which suite it executed. The SHA was onlyrecovered on 2026-08-14, two days later, by SSHing to the deployed checkout at
jochems-forge:~/.claude/repos/devwork-skillsand reading its HEAD.Why this is the sharp version of the problem rather than a mild one:
journal names the suite version, so a reader of the forge trail cannot tell which skill text
produced it.
re-verified against
origin/mainbefore filing, because a finding against two-day-old text mayalready be fixed. All 13 survived — but that verification pass was only possible because the
deployed checkout happened to be clean and reachable. Had it been dirty, or had it been pulled
in the meantime, the evidence would have been unreconstructable.
e3a5369, #33 — rc-checked stdout forhelper invocations). It was reframed as a generalisation to gate commands rather than filed as a
rediscovery. Without knowing the SHA, that call could not have been made.
Concrete shape this argues for: the first Phase Outcome of a run records the suite SHA and
whether the checkout was dirty, and every subsequent one carries it forward — cheap to write,
and it makes "is this finding still real?" answerable without archaeology.
Recorded in
sdlc-dogfood-run-reports/verity-slot4-230.md§1.Linked: this issue is relates_to #54 (recorded by the devwork pipeline).