Skip to content

Commit cacf044

Browse files
Sync Boatstack from Intelligence Flow Labs @ 2e2731b89000 (#115)
Co-authored-by: operator-stack-publisher[bot] <operator-stack-publisher[bot]@users.noreply.github.com>
1 parent 659eb92 commit cacf044

14 files changed

Lines changed: 325 additions & 40 deletions

CONTRIBUTING.md

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

33
# Contributing
44

5-
Boatstack is a generated content distribution. Propose changes to workflow semantics, templates, evidence rules, or generated presentation in [Intelligence Flow](https://github.com/operatorstack/intelligence-flow/tree/804141bc65d66fdb0a422a9c7c545a71180bffb1/labs/12-product-engineering-loop).
5+
Boatstack is a generated content distribution. Propose changes to workflow semantics, templates, evidence rules, or generated presentation in [Intelligence Flow](https://github.com/operatorstack/intelligence-flow/tree/2e2731b89000a3316a520552806c455fc4c32296/labs/12-product-engineering-loop).
66

77
The Boatstack repository receives product/runtime changes through a generated pull request. Review the PR's `UPSTREAM.json`, tests, adapter diff, and context-size change; do not hand-edit generated output on `main`. `.github/workflows` is the exception: it is Boatstack's executable control plane, excluded from scheduled projection and changed only through a separate manually reviewed Boatstack PR.
88

UPSTREAM.json

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
},
1313
"files": {
1414
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
15-
"CONTRIBUTING.md": "c7f3497bbe061860f2ecec201bbb9526f045585371c5f62db2b1b5ce17362bc5",
15+
"CONTRIBUTING.md": "7885795a89b06069d575aafee4ac7b86e67db5e249fa46a54ae1684ad1da8183",
1616
"README.md": "3ce3e95e511089b44e946a44b8d5f4f81d019ece5336db65b2cab1f9dc4d4dad",
1717
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
1818
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
1919
"assets/boatstack-portability.svg": "66dfdfa85db857b3bd18b32047a6975f1fbbfc4dc091158e8277193f9969a346",
20-
"boatstack/AGENTS.md": "39574398c3c3f82c22077299b45fd46a587926e1c9a35b66998c65ab8a756554",
20+
"boatstack/AGENTS.md": "bc76221e1fe90a91afbacd7c6bc9b41a70e6c10fc128c275a6a0b9bc094d9506",
2121
"boatstack/BUG-worktree-delivery-state.md": "02469cf51c3849dad5743783e248e5c04583e4240507fbef0e3f890cd6a95724",
2222
"boatstack/SKILL.md": "b393fe00f23f701e1310d7c1006f339935d3082c7adb9b35c038a3ad1bcc459e",
2323
"boatstack/agents/gemini.yaml": "cbf43b387399e456fa6178f86d83e6e35567e6142ff800f8de6ffca306fa963e",
@@ -50,13 +50,14 @@
5050
"boatstack/config_documentation_test.go": "0632366edc5e88145bb080083ea03c6515da07b0162ce404d63e51bb5bc0774e",
5151
"boatstack/decision.go": "257ca328da6ae19ab252f10ee5d06bd7daf49dd8141d083ab1b32f106ea7a94c",
5252
"boatstack/decision_test.go": "1a92ff832610f9559bd47ccac7fc1755a8b4f8261c35bc72a092830dff05f7c0",
53-
"boatstack/delivery.go": "9bdcfecae7564c34a0d374ddbba4f237b241085db5c9d5bda6c4afb801055b35",
54-
"boatstack/delivery_boundary_conformance_test.go": "800cd722d8d2a696a0529e8343d3523e453bb052f0917c8a2cad2990296ac1b3",
53+
"boatstack/delivery.go": "86150374b14982b1e589714d6ef6230348ef57b6824d4e1552b72289c044af4b",
54+
"boatstack/delivery_boundary_conformance_test.go": "c374eddf49b4597db78c0621f65f87199de9a26f1872ed88d9d790edf21fe3f2",
5555
"boatstack/delivery_migrate.go": "7566e49f9c1838d4d563866e941c7aacd61ac918c9e886222282398d287ca780",
5656
"boatstack/delivery_migrate_conformance_test.go": "b8ba53681e1d0361ac62b06586c62b7763d55a65b5427976b5289e1fb1503bdc",
5757
"boatstack/delivery_reactivation_test.go": "573a2dba0034bc4290478414e3bdd8670b06a326128eb0295d77e748ecc8689e",
5858
"boatstack/delivery_test.go": "45c48ff7581c911bcaf821c3e4241d4ae2a9bb4aa682485cc58b6ad8fe1c85bf",
5959
"boatstack/deliverycontrol_parity_test.go": "f8662cfc35043395a0e1eef8a87051c2120752f38b09c56b78f82896008f1b65",
60+
"boatstack/docs/control-law-scoping.md": "0ae984821248eabda8c0eeaf201b367991e6742984e7c718df20ecc24caee475",
6061
"boatstack/evidence.go": "497a31e6ff632cb1d7c3adfc9f269af3f6aa84e948dd5d417c162767542a27df",
6162
"boatstack/export.go": "b3e28b571024b1b7a97b28f226f7c89734c95dcf1854c3d1a6dc672f34d4ded7",
6263
"boatstack/export_test.go": "dce5aa3ab5499c82d05859cf86b46dfcee308482491366d83e10ca3fb8605bb6",
@@ -77,7 +78,7 @@
7778
"boatstack/flow_trace_test.go": "99f89a831e904f6a8ef710b6977ed3a808ce1c7ddfaba457b292d84f2ddca51b",
7879
"boatstack/go.mod": "6086ef1b2a83f5696190dca692c653925f27b61f652f659fd3fca43ed54a1641",
7980
"boatstack/go.sum": "26c315c867b11b886f3c9402fce7f341f6a9115a5d61f54afbb5e1b1fb5f6017",
80-
"boatstack/hooks.go": "c8606417aec79fdcf84b3420758e7d491c3757e7b3117c7fc8df2bf4b0733e03",
81+
"boatstack/hooks.go": "bed08eeaf80cc6c953c49463ffd5a6cf7bad595e8551e8d41c0a1580803c03cf",
8182
"boatstack/hooks_hydrate_test.go": "7beeb26b2b1398741e8a28963a9686e974047016cc736f233024004add1afc32",
8283
"boatstack/hooks_test.go": "fb75e3aabf2204871b3e6d16de98d26fb33b0ec19e41aae761cf1f34397c31f4",
8384
"boatstack/hydrate_runtime_test.go": "dbd5eae2ba85701e4af0430ba3a0d70ea98e028b66992bd4fc05f3f582398627",
@@ -130,7 +131,7 @@
130131
"boatstack/provision_test.go": "214e9edb991a66d5bbb696a7c1b63876d2f799f2cab4e3f40785f4e8f1eac57b",
131132
"boatstack/publication_ignored_repro_test.go": "b6f3aeb8ba22949ff9af7ac5afe8fb828385d9708d5d5893ef41f33a3de873e1",
132133
"boatstack/published_slice_routing_test.go": "ea7e7351018bc13dcd31c4b96f50f8bc230e8a1dbf7806fba32a12ae58923e7e",
133-
"boatstack/recovery.go": "7c06cdb52a31125cf3b944c304eca1df2273edc763242112527798bfb114874f",
134+
"boatstack/recovery.go": "e45b3b3c2cda85c2b887fae32ee46ad205f1f3f707e6dc7b46f68ef6746ab5aa",
134135
"boatstack/recovery_test.go": "29490e7477ba602491330036a491289dd9117b99ff862f66dae421ba17e04c9f",
135136
"boatstack/reexec.go": "fed55416479d7bd3e0c3637057ffe8eb58a032f93fc358f76df906ab7acc677b",
136137
"boatstack/reexec_unix.go": "ff86157a9aa20c82a56fcd859b70669b7eacf4e0a9f61a4546ef33808437939e",
@@ -176,10 +177,10 @@
176177
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
177178
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
178179
"docs/configuration.md": "df054f49d532c8b1b7d94184810d1b3b5bf18cdc30eb985b4b6d0639162e341a",
179-
"docs/evidence-engineered-coding.md": "8c9ac13f925f67db325db9163a1384aa01591d17af82e47e7447922585f62e16",
180+
"docs/evidence-engineered-coding.md": "96ac63e2275727ada464cc3c576340df98c1ae9a26bba407aa5a1d78c5448da7",
180181
"docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3",
181182
"docs/getting-started.md": "1dd4f4e2e636cc5adfc2f79939629701e171087c3d5e558cf919548b9224adfd",
182-
"docs/public-claims.json": "16d2327409e3bdaefab872aa46abeb88328a8ec263302ed0a4d5d48df431a392",
183+
"docs/public-claims.json": "3d74f2edfce7d7089496c22c8fcf0391ebef1fc07d5bc89153613b2d0d9356c6",
183184
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
184185
"docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6",
185186
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
@@ -193,7 +194,7 @@
193194
"labs/diagram-json/compiled/evidence.md": "1ba1c989ade070a8ef9a508fbd788d100d7292f2dbacbb2bce895468019f619d",
194195
"labs/diagram-json/compiled/tasks.json": "88f60851abf79d851e9fccc754ff3040034ae595306bc87d64784c19eb403e71",
195196
"labs/diagram-json/compiled/test-matrix.json": "424657ff505768e50fa113801fd8363364a18269d5297480907a993d44063a39",
196-
"labs/diagram-json/plan.lock.json": "59951495e1695536035673cac5c799a174d43ac1091e455d4cf4a0e29c9f9763",
197+
"labs/diagram-json/plan.lock.json": "ff12a3a7dfca9a8468935c28b96d3c85b8c4548ad6ee76e74b55f22d865ad7d7",
197198
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
198199
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
199200
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
@@ -292,15 +293,18 @@
292293
"release-notes/2026-07-25-per-worktree-operation-ledger.md": "d0d4495fe4406cf67e7475032e3fc9eb74ed02a3e68f4928c086b5518422b46c",
293294
"release-notes/2026-07-25-published-slice-correction-routing.md": "129cdd62c80c8b93060726027d68ba3abdb0bca1a1ce9e64d6053271af3fd082",
294295
"release-notes/2026-07-25-readme-simplified-technical-english.md": "c362f46702c38dda6b0301d05b95a067da617d170ddfcca22fd7eb9f6e2c1881",
296+
"release-notes/2026-07-25-recovery-tolerates-unrelated-stale-delivery.md": "70bf76d00d19455712d8e38c602b066982511aec89fed9aea2c196345ad783cb",
295297
"release-notes/2026-07-25-release-notes-simplified-technical-english.md": "70b273cbeb5ee46c49c10541540f31e8ca67a71102acfd47ae15451856c651db",
296298
"release-notes/2026-07-25-root-cause-operation.md": "5bf1f082e9123c5a7bcc8bc01b12e97b24b5ae15958577b4ff2a358994fca891",
297299
"release-notes/2026-07-25-runtime-simplified-technical-english.md": "917fbfb51ae56e5c6e0d9c705b84da492ef3b8f8782ea4b62635814259f11bb4",
298-
"release-notes/2026-07-25-update-publish-guard-unblock.md": "adf06ee02b8d3c995525bb9673c2f1fea66a147df8751d65885ced83da0e96e2"
300+
"release-notes/2026-07-25-update-publish-guard-unblock.md": "adf06ee02b8d3c995525bb9673c2f1fea66a147df8751d65885ced83da0e96e2",
301+
"release-notes/2026-07-26-guard-etxtbsy-retry.md": "4238591804be62f8b9a76dd5cda18923af60ef67932d40d70cab0d815124bcaf",
302+
"release-notes/2026-07-26-hidden-jflow-design-note.md": "f60ed9dbbfb46a172ac9d33dd758a3166f820007b1673029f29f0fbefa0e5c0a"
299303
},
300304
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
301305
"schema_version": 1,
302306
"source": {
303-
"commit": "804141bc65d66fdb0a422a9c7c545a71180bffb1",
307+
"commit": "2e2731b89000a3316a520552806c455fc4c32296",
304308
"path": "labs/12-product-engineering-loop",
305309
"repository": "operatorstack/intelligence-flow"
306310
}

boatstack/AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ change. Ask whether to (1) expand the current delivery, (2) split the shared
107107
boundary into a prerequisite delivery, or (3) apply bounded local containment
108108
and record the remaining risk.
109109

110+
State the law over the invariant and its failure class — never scoped to the one
111+
call site where you found the bug. A single shared resource is usually crossed by
112+
several boundaries; enumerate them all and extend the existing law to cover them
113+
rather than minting a near-duplicate for the second one. See
114+
[docs/control-law-scoping.md](docs/control-law-scoping.md) for the method and a
115+
worked example.
116+
110117
### 3. Add boundary-conformance tests
111118

112119
Tests must prove the control law, not merely exercise the implementation. Add

boatstack/delivery.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ func RecordChangeObservation(options ChangeObservationOptions) (ChangeObservatio
632632
if len(state.Slices) > 0 {
633633
observation.SliceID = state.Slices[len(state.Slices)-1].ID
634634
}
635-
states, statesErr := allManagedDeliveryStates(repo)
635+
states, _, statesErr := allManagedDeliveryStates(repo)
636636
if statesErr != nil {
637637
return ChangeObservation{}, DeliveryState{}, statesErr
638638
}

boatstack/delivery_boundary_conformance_test.go

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
//
1212
// control-law: stale-delivery-cannot-block-unrelated-feature
1313
// A stale/invalid delivery in the shared store must never escalate into a
14-
// repo-wide INVALID_STATE that blocks resolution of an unrelated new feature.
15-
// The ignored-deliveries filter is applied at the read-only ResolveNext
16-
// boundary BEFORE invalidity becomes fatal; the mutation boundary
17-
// (ActiveManagedDeliveries) stays fail-closed.
14+
// repo-wide block on resolution of an unrelated delivery. This holds at EVERY
15+
// read-only resolution boundary — ResolveNext (new work) and ResolveRecovery
16+
// (recovering an existing delivery) alike: each partitions the store instead
17+
// of failing closed and applies the ignored-deliveries filter BEFORE
18+
// invalidity becomes fatal, blocking only on a still-unignored invalid
19+
// delivery. The mutation boundary (ActiveManagedDeliveries) stays fail-closed.
1820
//
1921
// control-law: discard-preserves-published-authority
2022
// A delivery bearing published authority (any slice with a recorded PRState)
@@ -142,6 +144,88 @@ func TestResolveNextLeavesInvalidStateUntouched(t *testing.T) {
142144
}
143145
}
144146

147+
// The same law holds at the OTHER read-only resolution boundary: ResolveRecovery.
148+
// ResolveNext resolves new work; ResolveRecovery resolves an existing delivery
149+
// that hit a problem. Both scan the shared store, so both must tolerate an
150+
// unrelated stale delivery. These tests are the recovery-boundary twins of the
151+
// ResolveNext cases above — the defect that motivated generalizing the law was
152+
// that recovery had none of them and fell through to a repo-wide block.
153+
154+
// Positive + bypass conformance: an IGNORED invalid delivery no longer poisons
155+
// recovery of an unrelated healthy delivery on the current branch. The ignore
156+
// filter runs before invalidity can become fatal, so recovery selects and routes
157+
// the real target instead of blocking on abandoned state.
158+
func TestResolveRecoveryIgnoredInvalidDeliveryDoesNotBlockHealthyBranch(t *testing.T) {
159+
repo := nextTestRepo(t)
160+
branch, _ := gitCommand(repo, "branch", "--show-current")
161+
162+
writeNextDelivery(t, repo, "healthy-feature", "BUILD", 0)
163+
updateRecoveryDelivery(t, repo, "healthy-feature", branch, "", "")
164+
165+
writeInvalidDelivery(t, repo, "stale-one")
166+
if _, err := IgnoreDelivery(repo, "stale-one"); err != nil {
167+
t.Fatal(err)
168+
}
169+
170+
status, err := ResolveRecovery(RecoveryStatusOptions{Repo: repo, Message: "the test failed", SourceStage: "ci"})
171+
if err != nil {
172+
t.Fatal(err)
173+
}
174+
if status.VerificationStatus != "VERIFIED" || status.Feature != "healthy-feature" ||
175+
status.Lifecycle != "ACTIVE" || status.NextOperation != "repair_active" {
176+
t.Fatalf("ignored invalid delivery poisoned recovery of an unrelated healthy branch: %#v", status)
177+
}
178+
}
179+
180+
// Negative + relation conformance: a still-unignored invalid delivery does block
181+
// recovery, but the block names exactly the offending delivery and routes to the
182+
// discard-delivery remedy — request -> boundary -> decision.
183+
func TestResolveRecoveryUnignoredInvalidDeliveryBlocksWithDiscardRemedy(t *testing.T) {
184+
repo := nextTestRepo(t)
185+
branch, _ := gitCommand(repo, "branch", "--show-current")
186+
writeNextDelivery(t, repo, "healthy-feature", "BUILD", 0)
187+
updateRecoveryDelivery(t, repo, "healthy-feature", branch, "", "")
188+
writeInvalidDelivery(t, repo, "stale-one")
189+
190+
status, err := ResolveRecovery(RecoveryStatusOptions{Repo: repo, Message: "the test failed", SourceStage: "ci"})
191+
if err != nil {
192+
t.Fatal(err)
193+
}
194+
if status.VerificationStatus != "BLOCKED" || status.NextOperation != "discard-delivery" {
195+
t.Fatalf("unignored invalid delivery did not block with discard remedy: %#v", status)
196+
}
197+
found := false
198+
for _, slug := range status.Blockers {
199+
if slug == "stale-one" {
200+
found = true
201+
}
202+
}
203+
if !found {
204+
t.Fatalf("block did not name the offending delivery: %#v", status.Blockers)
205+
}
206+
}
207+
208+
// Failure-state conformance: ResolveRecovery is read-only. A blocking decision on
209+
// an invalid delivery must leave the offending state file byte-for-byte unchanged.
210+
func TestResolveRecoveryLeavesInvalidStateUntouched(t *testing.T) {
211+
repo := nextTestRepo(t)
212+
statePath := writeInvalidDelivery(t, repo, "stale-one")
213+
before, err := os.ReadFile(statePath)
214+
if err != nil {
215+
t.Fatal(err)
216+
}
217+
if _, err := ResolveRecovery(RecoveryStatusOptions{Repo: repo, Message: "boom", SourceStage: "ci"}); err != nil {
218+
t.Fatal(err)
219+
}
220+
after, err := os.ReadFile(statePath)
221+
if err != nil {
222+
t.Fatal(err)
223+
}
224+
if string(before) != string(after) {
225+
t.Fatalf("read-only recovery mutated the invalid state file\nbefore=%s\nafter=%s", before, after)
226+
}
227+
}
228+
145229
// ---- control-law: discard-preserves-published-authority ----
146230

147231
// Positive + relation conformance: an unpublished delivery is discardable; the

0 commit comments

Comments
 (0)