Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Contributing

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/2364eaedaefbe73d8996108dfac261c38b0ce2b3/labs/12-product-engineering-loop).
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/2126fde051cc11a8c3de9fff4fc17b5397240383/labs/12-product-engineering-loop).

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.

Expand Down
30 changes: 16 additions & 14 deletions UPSTREAM.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"canonical_context": {
"characters": 80569,
"estimated_tokens": 20143,
"characters": 80947,
"estimated_tokens": 20237,
"estimator": "ceil(total characters / 4); compactness signal, not provider billing",
"files": [
"product-engineering-loop/references/workflow.md",
Expand All @@ -12,14 +12,14 @@
},
"files": {
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
"CONTRIBUTING.md": "ea4d692766d22427d515ab944c9d692e862d63584c255fdecdb67e063cb32e32",
"CONTRIBUTING.md": "7338b0102e28024ac659eebe01be35bbcdf31aecb92e8c8dea15e5aa3abcf317",
"README.md": "3ce3e95e511089b44e946a44b8d5f4f81d019ece5336db65b2cab1f9dc4d4dad",
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
"assets/boatstack-portability.svg": "66dfdfa85db857b3bd18b32047a6975f1fbbfc4dc091158e8277193f9969a346",
"boatstack/AGENTS.md": "bc76221e1fe90a91afbacd7c6bc9b41a70e6c10fc128c275a6a0b9bc094d9506",
"boatstack/BUG-worktree-delivery-state.md": "02469cf51c3849dad5743783e248e5c04583e4240507fbef0e3f890cd6a95724",
"boatstack/SKILL.md": "b393fe00f23f701e1310d7c1006f339935d3082c7adb9b35c038a3ad1bcc459e",
"boatstack/SKILL.md": "1eb959a55c5462143c54f0016963542e7b28ceb5ed6ce1cfba942fde9595348a",
"boatstack/activation.go": "deb7712d20aed37371254596613bfaccfc05fcb59634408b03378d1a0bf693ea",
"boatstack/agents/gemini.yaml": "cbf43b387399e456fa6178f86d83e6e35567e6142ff800f8de6ffca306fa963e",
"boatstack/agents/openai.yaml": "68a30a60859556c5a26e16d184594ca243a6043d99c8cf7d66b5dd6d50a93cd1",
Expand Down Expand Up @@ -60,22 +60,23 @@
"boatstack/delivery_reactivation_test.go": "573a2dba0034bc4290478414e3bdd8670b06a326128eb0295d77e748ecc8689e",
"boatstack/delivery_test.go": "45c48ff7581c911bcaf821c3e4241d4ae2a9bb4aa682485cc58b6ad8fe1c85bf",
"boatstack/deliverycontrol_parity_test.go": "f8662cfc35043395a0e1eef8a87051c2120752f38b09c56b78f82896008f1b65",
"boatstack/denial.go": "656dc5e71a11daba25e7a23599f2e1aafa7a7439589af943cdccc72154a45816",
"boatstack/denial_test.go": "c480c0b2a489838b22b4d5ec20cc30ef1859cc0820a75974bc56a46c31f90041",
"boatstack/denial.go": "4132674988f35b776dc3207e5179dbb2e4da6b8e815a5913acfc3c8771f6ce51",
"boatstack/denial_test.go": "b865bf041b42ad4b904de0c7cf8d26ab7b5ba5bcc29407afe6caafa318f54791",
"boatstack/detached.go": "b0ea2a1f31bf2a2a83f6089a3065a9b47221194b64de48af9120046e6d70dee8",
"boatstack/detached_test.go": "6cc70d15baa9a69afacf66ea29ce112efeb166836acb0a52bf9c4bb4c898cee5",
"boatstack/docs/control-law-scoping.md": "0ae984821248eabda8c0eeaf201b367991e6742984e7c718df20ecc24caee475",
"boatstack/evidence.go": "497a31e6ff632cb1d7c3adfc9f269af3f6aa84e948dd5d417c162767542a27df",
"boatstack/export.go": "1a01d19ac6e8418febf93f9ebf1a466a46da4b09eea7bafe6ccfb6cfb0f73a6d",
"boatstack/export.go": "56dd395382e033cc919ae8894722d5c6d135ffdee9153edd900dd064c3d08962",
"boatstack/export_test.go": "dce5aa3ab5499c82d05859cf86b46dfcee308482491366d83e10ca3fb8605bb6",
"boatstack/flow_coding.go": "9fa53a0204f98a25f97775c3acf37392a591c14ce850b44aa587b5806e770bb9",
"boatstack/flow_coding_test.go": "dddcd7a85892d4fa10af42739d4c1ff265721b0313e27b6e7a1bbb019d5c3b51",
"boatstack/flow_control.go": "23b539c0d2dfcabb4606b94abeee1b25754cd9627c3c39f08ddc3c49fed81615",
"boatstack/flow_control_test.go": "d52e095f2e0f18067abe03e3b5f7c98bc30f8b1c8f5230103797c599aec95013",
"boatstack/flow_control.go": "76b78c69305475f827ab512cf5e78ae22e6a1b40c4e8b2387b72e00fee09bf07",
"boatstack/flow_control_test.go": "02d788c83be55ebd79ffc73875bfd019de45325151eb1f70f506980eb8e77f29",
"boatstack/flow_drive.go": "a501ceda390dfd3605e22cf7ecfa15f9d50240b3fac6ebb2bb2d80c615d0a9fc",
"boatstack/flow_drive_conformance_test.go": "23edea926c271a1f5718fb9dae1da11e4bf03cceb1357290cd61cd8ffb73beda",
"boatstack/flow_guard.go": "dd18524d95f4a220cfd3d11b11003dacc52120785ee0ccdbeceb2307fab55872",
"boatstack/flow_guard_test.go": "8ba75f11ddd080427c15bd7e25f7d03c1b746a2f587c212cea0e710337d1c0e1",
"boatstack/flow_planning_prescribe_conformance_test.go": "c2fa2566b0676f34a777764ade87a0670d41413d052a9a339e01bdb6a9a8699b",
"boatstack/flow_prescribe_conformance_test.go": "e2287aa079b7aafaf822e1f752a1bb5017acda811363e576eeff793347d0d5c8",
"boatstack/flow_report.go": "9e58cec51c6c903847f3ebc79cd6bf25e2f91d14b81811e82e5f4e026a7b71a3",
"boatstack/flow_report_test.go": "eae00f2b8ead4f1ec20e1f1bc47db4c53a36048bb84eca9bea4f1a2105bdcdde",
Expand Down Expand Up @@ -152,7 +153,7 @@
"boatstack/references/host-hook-contracts.md": "2a89d44d0e418a53f2e3b6300fed957cdf878f45ea97ce24b55b66065f0eaa1d",
"boatstack/references/irreversible-operation-boundary.md": "e0076f0fea3bf729b2e9bdf353eaeaaf7cdafabfaf26b8d9b27287e5414c2441",
"boatstack/references/portability.md": "fb683095991bb0cb06ec56fb8884c49038b283172a7d2f8b203483b7cacb4bae",
"boatstack/references/workflow.md": "81da3ea831ef244eb03b09e1989052b6f52db816e3d65be98da3ab9d5cc31969",
"boatstack/references/workflow.md": "d6174f8d546e75829a35418741e94a5606d18314e4a2d8e0bb04394745f335bd",
"boatstack/release.go": "82dcb4ca59e8c79a68d5333d650f90e64abd448d04e0c6f504fdf07f42b5ed76",
"boatstack/release_test.go": "5cf2d76fe9b836a91ca68eba53d5585e2c4be5b9421aaf939ea0723063a24690",
"boatstack/repair_state_test.go": "f3779ac47c3db3927175a545728d3b2e020dbc85f41394d8235753b52afc3739",
Expand Down Expand Up @@ -190,10 +191,10 @@
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
"docs/configuration.md": "060775c73431f28bd16066bdf9e0f89034d2855c7ca0f5544f660d24b91211d0",
"docs/evidence-engineered-coding.md": "0083581913336f9612f321997a3e9afb8b7f2549e41d6fbae122920174ae4779",
"docs/evidence-engineered-coding.md": "e5c48eb66d9ac2967aa41b8ba972f0d85d7fb95cdaa2fe1019f45bd544d73eb6",
"docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3",
"docs/getting-started.md": "51c2823f21e35140d31e6d5083dc4b89fddd24721ac6acc474154a4da53ee9f8",
"docs/public-claims.json": "aa2ee5ecd6a3f29d5dd3c4e538d29931191606a52fad6433d43184af814334c3",
"docs/public-claims.json": "b723b764dcb7ca02f339a36e837a6fcf7d9b59ab881878e0ea1aab9c3a101070",
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
"docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6",
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
Expand All @@ -207,7 +208,7 @@
"labs/diagram-json/compiled/evidence.md": "1ba1c989ade070a8ef9a508fbd788d100d7292f2dbacbb2bce895468019f619d",
"labs/diagram-json/compiled/tasks.json": "88f60851abf79d851e9fccc754ff3040034ae595306bc87d64784c19eb403e71",
"labs/diagram-json/compiled/test-matrix.json": "424657ff505768e50fa113801fd8363364a18269d5297480907a993d44063a39",
"labs/diagram-json/plan.lock.json": "9c2377941197d6bd160f338e0bc55dd74f9118844291b5ee73a17867757a5edb",
"labs/diagram-json/plan.lock.json": "4c31e6695c8cc726d795e8dd39d8f7ba84d208a615786d674ef445e91e60b52b",
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
Expand Down Expand Up @@ -326,13 +327,14 @@
"release-notes/2026-07-27-discoverable-planning-errors.md": "d8099d1a6cd1805c3fcd446d9fa95739dec93e57ff421ecf4f99562b143c9966",
"release-notes/2026-07-27-guard-dual-reward-corpus.md": "6bec0385c6c553f00517259821e502796ca1b1907aeab718a287560e3e0fa0d6",
"release-notes/2026-07-27-invalid-delivery-block-actionable.md": "8fac8e3921e2285291703efa46e624b72cb5bac1b8492beca4c4b633abb5ba16",
"release-notes/2026-07-27-prescriptive-planning-closure.md": "e544408e1c3cceb0cb1979833ea120853c38020933439b39e7f009f454b9661e",
"release-notes/2026-07-27-read-only-inspection-pipelines.md": "0963286371e9a12592915c23a958dd013bf2a35e9fca6921691bc8bb3c3d8dc8",
"release-notes/2026-07-27-sandboxed-migration-grading.md": "03cebc372bbdfed37cc70d18f3b6374d1aa5e585bafefa073dbcced58bd0336a"
},
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
"schema_version": 1,
"source": {
"commit": "2364eaedaefbe73d8996108dfac261c38b0ce2b3",
"commit": "2126fde051cc11a8c3de9fff4fc17b5397240383",
"path": "labs/12-product-engineering-loop",
"repository": "operatorstack/intelligence-flow"
}
Expand Down
2 changes: 1 addition & 1 deletion boatstack/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Before starting `/auto-plan` for a new feature, check `next-status --repo . --js
13. If Spec Kit is installed, use its constitution/specify/clarify/plan/tasks/analyze/checklist flow as an artifact generator. The canonical artifact contract remains authoritative.
14. For every planned validation, record the exact `criteria` it can support plus `run`, `origin`, `oracle`, and `independence`. Commands, automated tests, external checks, and named human review procedures are all valid forms, but an ambiguous claim without a threshold/rubric and authorized decision remains `BLOCKED`.
14. For every external write, record `affected_paths` plus side-effect kind, immutable target identity, reversibility, failure policy, and `destructive: false`. Reject ambiguous reset rollback or target names.
15. Write only Markdown feature artifacts, including the canonical structured `plan.md`. Put its authoritative JSON inside the marked Boatstack block and run `boatstack-helper check-plan --plan <feature>/plan.md`; this command is read-only. If the host blocks its ordinary Markdown writer, pass the document to `boatstack-helper planning-write --repo . --feature <feature> --artifact <known-name>` on stdin. Never use arbitrary shell redirection to evade a host write boundary.
15. Write only Markdown feature artifacts, including the canonical structured `plan.md`. Author every feature artifact through the owned channel: pass the document to `boatstack-helper planning-write --repo . --feature <feature> --artifact <known-name>` on stdin — it is the primary writer for `.product-loop/features/`, not a fallback, and it remains available after the planning latch denies raw writes. Put the authoritative JSON inside the marked Boatstack block and run `boatstack-helper check-plan --plan <feature>/plan.md`; this command is read-only. The host's ordinary Markdown writer may be used only where the host explicitly permits it. Never use arbitrary shell redirection to evade a host write boundary.
16. Keep implementation tasks separate from publication authority. Internal phases remain tasks inside one delivery slice. When the accepted outcome explicitly requires multiple PRs, declare ordered `delivery_slices`; assign every task exactly once and give each slice its own optional base/head branch contract. Plan approval approves this structure but never authorizes a push or PR.
17. End with a **draft**, never an implied approval. Do not generate executable task state, JSON artifacts, locks, or implementation changes from `auto-plan`.

Expand Down
11 changes: 11 additions & 0 deletions boatstack/denial.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,17 @@ func denialFor(host string, finding SafetyFinding) Denial {
}
d.Qualifier = "plan gate"
d.Detail = fmt.Sprintf("Product mutation is denied because %s is at %s.%s Continue with `%s`; unrelated task completions do not authorize implementation.", target, finding.WorkflowStage, attempted, next)
// A planning-state denial must name the owned authoring channel, not just
// the cleanup verb — otherwise the corrective move (planning-write) is
// discoverable only by failing again.
// control-law: prescriptive-closure-every-stage-names-a-runnable-command
if finding.Source == "planning-state" {
slug := "<feature>"
if finding.BlockingFeature != "" {
slug = finding.BlockingFeature
}
d.Detail += fmt.Sprintf(" Planning Markdown is authored through the owned channel: `boatstack-helper planning-write --repo . --feature %s --artifact <name>` with the document on stdin — never a raw host write into `.product-loop/features/`.", slug)
}
d.Reassurance = reassureUntouched
return d

Expand Down
26 changes: 26 additions & 0 deletions boatstack/denial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,32 @@ func TestDenialRenderModesCarryTheSameInformation(t *testing.T) {
}
}

// control-law: prescriptive-closure-every-stage-names-a-runnable-command — a
// planning-state plan-gate denial names the owned authoring channel
// (planning-write), not just the cleanup verb, in every render mode.
func TestPlanningPhaseBypassDenialNamesOwnedChannel(t *testing.T) {
finding := SafetyFinding{
Category: "workflow-phase-bypass", Source: "planning-state",
WorkflowStage: "INVALID_STATE", NextOperation: "repair-state",
BlockingFeature: "sample-feature",
}
d := denialFor("claude", finding)
for mode, name := range map[RenderMode]string{RenderPlain: "plain", RenderMarkdown: "markdown", RenderANSI: "ansi"} {
out := d.Render(mode)
if !strings.Contains(out, "repair-state") {
t.Fatalf("%s denial dropped the recovery verb: %q", name, out)
}
if !strings.Contains(out, "planning-write --repo . --feature sample-feature --artifact <name>") {
t.Fatalf("%s denial must name the owned planning-write channel: %q", name, out)
}
}
// A non-planning finding must not gain the planning guidance.
other := denialFor("claude", SafetyFinding{Category: "workflow-phase-bypass", Source: "delivery-state", WorkflowStage: "BUILD", NextOperation: "plan-gate"}).Render(RenderPlain)
if strings.Contains(other, "planning-write") {
t.Fatalf("non-planning denial must not mention planning-write: %q", other)
}
}

func TestDenialReassuranceIsCategoryAware(t *testing.T) {
// A blocked-before-effect denial reassures that nothing was written.
tamper := denialFor("claude", SafetyFinding{Category: "workflow-state-tamper"}).Render(RenderPlain)
Expand Down
Loading
Loading