Skip to content

Commit 23501bc

Browse files
committed
chore(D0142): cut 5.0.1, and re-baseline the corpus figure from a measurement instead of a memory
Version 5.0.1 across the authoritative locations, the changelog section cut from its fragment, and hand-authored notes for a reader outside this repository. The release gate's verify lane reports 52 red criteria against a recorded baseline of 50, and the baseline blocks in BOTH directions, so that had to be explained rather than waved through: a count above the line is supposed to mean a new dead selector nobody guarded. It is not one here, and that was settled by execution. `git diff v5.0.0..HEAD -- sdlc-studio/` shows no story file changed at all - the only artefact diffs are derived indexes and the three specs. The delivered commit touches one skill test, and only to wrap a call in `redirect_stdout`. A red criterion is a story `Verify:` line failing against a test file, and neither side of that moved. What moved is the denominator: 1,906 criteria across 670 stories now, against a recorded 1,918 across 673. Two runs that disagree on how many criteria EXIST were not measuring the same set, so the gap between their red counts carries no information about regression. The recorded figure is treated as unreproducible rather than as a bar that has been breached. This is the failure the baseline file was written about, happening to the baseline file. Its header records the number being wrong four times - 106, 53, 58, 50 - and states the argument outright: a number nobody re-measures is a number that is wrong. Carrying 50 forward a fifth time because it is what is written down would be that mistake again, so the baseline is set from this run's own measurement and D0142 records why. Stated as the weakness it is: 52 rests on one reading, which is the standing 50 had. It is better only in being current and in naming the tree it was taken on. The scheduled corpus lane is what makes it a series. The release proceeds with that lane red, on the same footing as v5.0.0 under D0137: the stale selectors are disclosed v5.1 debt, and repairing them in bulk would convert a visible stale selector into an invisible vacuous one. Also corrected: the runbook's `record-green` row documented a `--gate <which>` flag that does not exist on the command. Written from the intent of D0141 rather than from the CLI, and found by trying to run it. The `dead-flags` lane does not reach `reference-*.md`, so nothing caught it - which matters more than the typo, because the runbook is the document every session is told to read before acting. Also fixed, and it blocked this commit twice: `test_the_guard_reddens_on_a_mutated_cell` wrote the LIVE `.claude/skills/sdlc-studio/SKILL.md` and restored it byte-for-byte in a `finally`. That reads as safe and is not. `repo_writes` reports a restored path deliberately, because a run that edits a tracked file and puts it back has raced every concurrent reader of it - and it left the skill's own entry point one interrupted run away from being what a fixture destroyed. The mutation now lands on a symlinked copy: every child of the skill tree is symlinked and only `SKILL.md` is a real file, so path resolution behaves as it does live at no copying cost, and a positive control asserts the UNmutated guide resolves through that root. Killed by mutating `check_loading_guide` to return `[]`. This is `repo-writes` catching a PRE-EXISTING writer rather than a fresh mistake - its first such catch since it shipped. The lane earned its place at a release boundary, which is where the four incidents it was built after were each found by something unrelated. Refs: D0142, BG0575
1 parent 2588384 commit 23501bc

14 files changed

Lines changed: 123 additions & 79 deletions

File tree

.claude/skills/sdlc-studio/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: "The antidote to vibe coding: a full software engineering team at y
44
license: MIT
55
compatibility: "Requires Python 3.10+ for bundled scripts; gh CLI (authenticated) for GitHub sync commands. Agentic wave execution (--agentic) is Claude-Code-only."
66
metadata:
7-
version: "5.0.0"
7+
version: "5.0.1"
88
openclaw: { "emoji": "📋", "requires": { "bins": ["python3"] } }
99
allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent
1010
---

.claude/skills/sdlc-studio/reference-sprint-toolchain.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Read this at plan time. `sprint plan` prints it.
7676
| Do | Command | Instead of |
7777
| --- | --- | --- |
7878
| Compose the changelog section | `release_cut.py changelog-cut --version <v>` | hand-merging fragments |
79-
| Stamp the commit the gate passed on | `release_cut.py record-green --commit <sha> --gate <which>` | a green claim naming no gate |
79+
| Stamp the commit the gate passed on | `release_cut.py record-green --commit <sha>` | tagging on a green nobody recorded |
8080
| Refuse a tag the gate never covered | `release_cut.py tag-check --version <v>` | tagging on memory |
8181
| Publish the release and its artefacts | your project's release automation, triggered by the tag | a hand-uploaded artefact, which is the step that gets skipped |
8282

.claude/skills/sdlc-studio/templates/version.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
schema_version: 3
66
upgraded_from: null # Previous version (null for new projects)
77
upgraded_at: null # ISO timestamp of upgrade
8-
skill_version: "5.0.0" # SDLC Studio version that created/upgraded
8+
skill_version: "5.0.1" # SDLC Studio version that created/upgraded
99
created_at: "{{created_at}}"

CHANGELOG.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [5.0.1] - 2026-08-12
11+
12+
### Fixed
13+
14+
- **The documented verified install could never complete, at any version, and now does (BG0575).**
15+
README and the website both offer `SDLC_STUDIO_REQUIRE_CHECKSUM=1` with a pinned tag as the path
16+
for a reader who will not accept an unverified download. It refused every time. `install.sh`
17+
looked for a `.sha256` sidecar beside GitHub's GENERATED source archive, and GitHub serves no
18+
such sidecar at any version - so the digest resolved empty, the requirement made empty fatal,
19+
and the one command offered to that reader was the one command guaranteed to fail. `install.ps1`
20+
carried the identical defect against the `.zip`. Nothing exercised either, so both were
21+
consumer-facing from the day they were written and green the whole time.
22+
A tagged version now prefers a release ASSET that this project builds from the tag and publishes
23+
with its digest in the same automated step (`.github/workflows/release.yml`), so both halves of
24+
the pair are ours and cannot drift. GitHub's generated archives are deliberately NOT verified:
25+
they are regenerated rather than published, and a recorded digest for one can stop matching with
26+
nobody touching the tag - which reaches a user as `Checksum mismatch`, indistinguishable from an
27+
attack. Falling back to the unverified archive now happens on a 404 and only on a 404, because
28+
reading a fault as an absence silently downgrades a user from bytes we published to bytes we did
29+
not. That distinction needed the HTTP status to be READ rather than inferred: `curl -f` exits 22
30+
for every status at or above 400, so a 403, a rate-limiting 429 and a CDN 503 were
31+
indistinguishable from a genuine 404 by exit code alone - the first version of this fix claimed
32+
to separate them and did not. `wget` collapses the same range onto exit 8 and has its `-S` trace
33+
read instead. Tags before v5.0.1 have no assets and still refuse, honestly, rather than widening
34+
what counts as verified.
35+
The regression test drives the shipped `install.sh` end to end with a `PATH`-stubbed `curl` over
36+
a local origin - no network, and no base-URL argument added to production for a test's benefit.
37+
It has to: a unit test of `verify_download` cannot see this defect, because that function is
38+
correct and always was, and the bug is the URL handed to it. **The PowerShell half is not
39+
verified locally** - `pwsh` is absent on the development machine - and is covered instead by a
40+
green-and-red pair in the `windows-smoke` job, which runs `install.ps1` under real PowerShell on
41+
every push. Asserting over the text of `install.ps1` would have been a weaker claim than the
42+
criterion, and is not what shipped.
43+
Nobody should publish a digest for a generated archive later: a user pinning it via
44+
`SDLC_STUDIO_SHA256` would now mismatch against the asset.
45+
46+
<!-- section: Added -->
47+
- **Releases publish their own assets, and the runbook finally has a step for the release
48+
(BG0575, CR0545).** Everything after the tag was un-tooled: `release_cut.py` stopped at
49+
`tag-check`, and `reference-sprint-toolchain.md` - the document AGENTS.md tells every session to
50+
read BEFORE starting a step - had no row for release at all. It was paid for twice. The v4.1.0
51+
Release carries an empty asset list, and v5.0.0 was tagged and pushed with no Release published
52+
at all, which matters more than it reads: `version_check.py` polls `releases/latest`, so every
53+
installed copy still reported v4.1.0 as current and prompted nobody to upgrade. A tag without a
54+
Release is, to the tool's own update mechanism, unreleased.
55+
`.github/workflows/release.yml` now builds a `.tar.gz` and a `.zip` from the tag with pinned
56+
commands, records each digest from the file it actually uploads, verifies both sidecars before
57+
publishing anything, and creates or completes the Release. It binds to the tag push rather than
58+
to a runbook line for the reason the history shows: the assets are what the verified install
59+
depends on, and a step that depends on somebody remembering is the same defect one version
60+
later. A `workflow_dispatch` leg exists for a tag pushed before the workflow did, and for
61+
recovery. The runbook gains a Release section naming each command beside the hand-rolled shape
62+
it replaces.
63+
1064
## [5.0.0] - 2026-08-12
1165

1266
### Fixed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
Ask for software in plain language. The team plans it, builds it, tests it, and proves it is done.
88

9-
**Version 5.0.0**
9+
**Version 5.0.1**
1010

1111
[![Licence: MIT](https://img.shields.io/badge/licence-MIT-blue.svg)](LICENSE)
1212
[![Lint](https://github.com/DarrenBenson/sdlc-studio/actions/workflows/lint.yml/badge.svg)](https://github.com/DarrenBenson/sdlc-studio/actions/workflows/lint.yml)

changelog.d/BG0575.md

Lines changed: 0 additions & 50 deletions
This file was deleted.

docs/release-notes-v5.0.1.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ listed by id in [docs/known-issues.md](known-issues.md) and triaged to v5.1. The
7878
generated from the bug corpus and guarded in both directions, so a finding filed after it was
7979
written cannot silently be missing from it.
8080

81+
**The stale-criteria count, re-measured.** v5.0.0's notes reported 50 executable acceptance
82+
criteria failing when run, of 1,918 across 673 stories at Done. Re-run for this release the
83+
figure is **52 of 1,906 across 670**. No story file changed between the two tags, so the
84+
denominators disagreeing means the two runs were not measuring the same set - and the gap
85+
between their red counts therefore says nothing about anything getting worse. The earlier
86+
reading could not be reproduced and is not carried forward.
87+
88+
That is the fourth time this number has moved in this project's own records (106, 53, 58, 50,
89+
now 52), which is the argument for putting it on a schedule rather than a footnote to it. The
90+
repairs remain a v5.1 sweep with their own review: a repair that merely makes a criterion pass
91+
converts a visible stale selector into an invisible vacuous one, which is worse than the red it
92+
replaced.
93+
8194
- [README](../README.md) - installation and quick start
8295
- [v5.0.0 release notes](release-notes-v5.0.0.md) - what the v5 line actually is
8396
- [CHANGELOG.md](../CHANGELOG.md) - the per-unit record

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sdlc-studio",
3-
"version": "5.0.0",
3+
"version": "5.0.1",
44
"description": "Claude Code skill for managing the full software development lifecycle",
55
"private": true,
66
"scripts": {

sdlc-studio/decisions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ agents read, so a decision is referenced once, not pasted N times.
153153
| D0139 | v5.0.0's release notes are HAND-AUTHORED for a reader outside this repository: what v5 is, the upgrade path from v4.1, what changed, and the known issues with their ids and v5.1 target. `changelog.py compose` still runs, because the release gate refuses on the 34 uncomposed fragments, but its output ships as the linked CHANGELOG rather than as the notes themselves. | Operator ruling, 2026-08-11. The composed draft is 4,001 lines and carries unit ids on essentially every bullet - D0135 already recorded that this is what compose produces and that it is the reason the notes could not simply be the composed body. What that ruling deferred to this charter, this one settles: both artefacts ship, with distinct jobs. The composed log is the per-unit record and an adopter auditing a specific change needs it, so dropping it would lose real evidence; it is simply not something a person deciding whether to upgrade can read. The hand-authored page is the thing that decides an upgrade, and it is the only place the 38 deferred bugs from D0136 can be disclosed in a form that means anything - a bug id inside a 4,001-line log is disclosed in the same sense that a rule stated in AGENTS.md with no gate behind it is enforced. | accepted | -- | 2026-08-11 |
154154
| D0140 | US0469, US0474 and US0475 are OUT of the v5.0.0 release scope and stay at Ready. SC0007's scope rule listed them beside the eight units awaiting sign-off, as though they were delivered work needing only a signature. They are not: none carries a changelog fragment, and one names a test file that has never existed. They are planned, unbuilt EP0171 stories, and they are not defects, so they hold no release bar. They are carried to v5.1 as ordinary backlog. | Checked rather than assumed, which is the whole point of recording it. `git log -S` against each id returns only planning commits; `changelog.d/US0469.md`, `US0474.md` and `US0475.md` do not exist; `.claude/skills/sdlc-studio/scripts/tests/test_close_review_record.py`, named in US0475's Affects, is absent from the tree. A charter that lists unbuilt work in the same breath as work awaiting a signature invites exactly the error this repository filed as a High bug - a unit's status read from its neighbours rather than from itself. The alternative was to build three stories inside a release cut, which is scope the tag does not need and review capacity the run does not have. Naming them here means the next reader finds them carried deliberately rather than dropped quietly. | accepted | -- | 2026-08-11 |
155155
| D0141 | v5.0.0 is tagged on a commit whose `gate.py --boundary release` is GREEN, with `gate.py --release`'s verify lane RED at 50 criteria. `release_cut.py record-green` stamps the boundary gate, not the whole-workspace one, and this decision records which gate was stamped so the stamp cannot be read as more than it is. | An independent review of the release plan established that `record_green` performs no gate at all - it writes the commit id to a file - so nothing mechanical distinguishes a stamp made after a green run from one made after none. That makes the choice of gate a judgement, and a judgement belongs on the record rather than in a command's silence. The boundary gate is the one doctrine names for a release, and it passed: conformance 0 non-conformant, reconcile 0 drift, duplicate-id clean, and release-rehearsal walking greenfield init and a v4-era upgrade end to end. The whole-workspace gate additionally executes every acceptance criterion in the corpus, and 50 of 1,918 fail. D0137 already ruled those into v5.1 as their own sweep, for reasons that still hold: they are stale selectors rather than broken features, and a repair that merely makes a criterion pass converts a visible stale selector into an invisible vacuous one. Repairing 50 of them inside a release cut, without a review each, is precisely the trade that ruling refused. The cost is stated rather than hidden. v5.0.0 ships with 50 executable criteria that fail when run, the release notes say so with the number, `tools/verify-corpus-baseline.txt` records it as the figure the scheduled lane holds against in both directions, and the write-time guard means the set is closed and draining rather than open and growing. What this decision buys is that the next reader can tell which gate was green, instead of inferring it from a stamp that would look identical either way. | accepted | -- | 2026-08-12 |
156+
| D0142 | The corpus verification baseline is re-set from this run's own measurement: 52 red criteria of 1,906 across 670 stories, measured by `gate.py --release` at 2588384b on 2026-08-12. The recorded 50 of 1,918 across 673 could not be reproduced and is not carried forward. v5.0.1 is tagged with the verify lane red at that figure, on the same footing as v5.0.0 under D0137. | The baseline demands NO WORSE and blocks in both directions, so 52 against a recorded 50 had to be explained rather than waved through - a count above the line is supposed to mean a new dead selector nobody guarded. It is not that here, established by execution rather than impression. `git diff v5.0.0..HEAD -- sdlc-studio/` shows no story file changed at all; the only artefact diffs are derived index files and the three specs. The delivered commit touches exactly one skill test, `test_sprint.py`, and only to wrap a call in `redirect_stdout`; that test passes and no story selects it in a way the wrapper could affect. A red criterion is a story `Verify:` line failing against a test file, and neither side of that moved. What did move is the DENOMINATOR: 1,906 executable criteria across 670 stories now, against the recorded 1,918 across 673. Two measurements that disagree on how many criteria exist were not measuring the same thing, so the delta between their red counts carries no information about regression. The recorded figure is therefore treated as unreproducible rather than as a lower bar that has been breached. This is the failure the baseline file was written about, happening to the baseline file. Its own header records the number being wrong four times - 106, then 53, then 58, then 50 - and states the argument plainly: a number nobody re-measures is a number that is wrong. Carrying 50 forward a fifth time because it is what is written down would repeat exactly that, and re-baselining to a figure this run actually measured is what the file asks for. Stated as a weakness rather than left implicit: 52 rests on ONE measurement, which is the same standing the 50 had. It is better only in being current and in naming the tree it was taken on. The scheduled corpus-verify lane is what turns a single reading into a series, and it now has a figure to move from. The release proceeds because the lane's redness is the disclosed v5.1 stale-selector debt ruled by D0137, already named in the v5.0.0 notes and shipped over once. Nothing about the count's provenance changes what a consumer of v5.0.1 gets: the repairs are still a v5.1 sweep, because a repair that merely makes a criterion pass converts a visible stale selector into an invisible vacuous one. | accepted | -- | 2026-08-12 |
156157

157158
## Notes
158159

sdlc-studio/prd.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Product Requirements Document
22

33
**Project:** SDLC Studio
4-
**Version:** 5.0.0
4+
**Version:** 5.0.1
55
**Last Updated:** 2026-07-14
66
**Status:** Generated (brownfield extraction; epics/stories validated and closed out 2026-07-09, commit 841471e)
77

@@ -11,7 +11,7 @@
1111
> tests validate the spec against the implementation. Confidence markers and
1212
> status values are defined at the foot of this document.
1313
>
14-
> **Coverage:** v5.0.0 as released, plus the work sitting on `main` under
14+
> **Coverage:** v5.0.1 as released, plus the work sitting on `main` under
1515
> `CHANGELOG.md` `[Unreleased]`. The v5 line covers the refusal gates (the
1616
> breakdown gate, the two-role review, the executable-criteria gate on Done, the
1717
> verifier ratchet), the evidence lane (mutation evidence, vacuous-verifier

0 commit comments

Comments
 (0)