From 75ddeda6c73734c883ba5dcc820ec4d8613bda46 Mon Sep 17 00:00:00 2001 From: "operator-stack-publisher[bot]" Date: Tue, 21 Jul 2026 23:55:37 +0000 Subject: [PATCH] Sync Boatstack from Intelligence Flow Labs @ cb079d704e3b --- CONTRIBUTING.md | 2 +- UPSTREAM.json | 28 +++++----- boatstack/SKILL.md | 19 +++---- boatstack/export.go | 6 +-- boatstack/plan.go | 4 ++ boatstack/plan_validation.go | 23 ++++++++ boatstack/plan_validation_test.go | 53 +++++++++++++++++++ boatstack/pr.go | 39 ++++++++++++++ boatstack/runtime.go | 1 + docs/evidence-engineered-coding.md | 2 +- docs/public-claims.json | 24 ++++----- labs/diagram-json/plan.lock.json | 2 +- .../2026-07-22-boundary-analysis-dx.md | 3 ++ .../2026-07-22-boundary-oracle-loop.md | 7 +++ 14 files changed, 173 insertions(+), 40 deletions(-) create mode 100644 release-notes/2026-07-22-boundary-analysis-dx.md create mode 100644 release-notes/2026-07-22-boundary-oracle-loop.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 037f196..6760acc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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/e18c8a4e2a77a63476b28f56c84c29289f2b4a47/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/cb079d704e3b0d82fa88b4318d3fb89fbd96723e/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. diff --git a/UPSTREAM.json b/UPSTREAM.json index 8d3677f..6c9072f 100644 --- a/UPSTREAM.json +++ b/UPSTREAM.json @@ -12,12 +12,12 @@ }, "files": { ".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957", - "CONTRIBUTING.md": "47d3f95927671ac039764c55029d9522eb094611145605b22c235cea719752dc", + "CONTRIBUTING.md": "bef7d513b31e781826809b5ab637be803775bd3972c38a16df6731885b9a15a6", "README.md": "8d481f8e395346400726d02f760f831a8b11062de18b7a76fe4cf00e5e12ca08", "assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63", "assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5", "assets/boatstack-portability.svg": "66dfdfa85db857b3bd18b32047a6975f1fbbfc4dc091158e8277193f9969a346", - "boatstack/SKILL.md": "ab0182a73bf42cf01ef0bb99486dd48d83673a60377bae2b5ecdf27022fb5395", + "boatstack/SKILL.md": "fdc85bd940bc4a4c5bf3d6543f24e3d345cac457057f1adae8d52f01282f5c75", "boatstack/agents/gemini.yaml": "cbf43b387399e456fa6178f86d83e6e35567e6142ff800f8de6ffca306fa963e", "boatstack/agents/openai.yaml": "68a30a60859556c5a26e16d184594ca243a6043d99c8cf7d66b5dd6d50a93cd1", "boatstack/assets/templates/adr.md": "c577a3c1c1319061f61deb053597e6e853657022185fe28b8f733327e2a78565", @@ -41,7 +41,7 @@ "boatstack/delivery.go": "6ff71b6f4ae4f85a184edaf453b5933a79366e36137802fda056e58f83fe319c", "boatstack/delivery_test.go": "e0323d4e2ef9c74a07c799cf42df91c90a43d61a0fdfddd8b10c5e3e27d5e492", "boatstack/evidence.go": "497a31e6ff632cb1d7c3adfc9f269af3f6aa84e948dd5d417c162767542a27df", - "boatstack/export.go": "eab2b510bdb2730d0edeb691fba63a6092e2eefcd06adb4b28b946ae1a235209", + "boatstack/export.go": "014c76fdf13a0a733270f6db383cdd10daf4ca7094fa6a33c27217c5addf44b3", "boatstack/export_test.go": "27f9895f39d0958b5b4824193865a8a30333db709e5b91788aff3d49304457ed", "boatstack/go.mod": "6086ef1b2a83f5696190dca692c653925f27b61f652f659fd3fca43ed54a1641", "boatstack/go.sum": "26c315c867b11b886f3c9402fce7f341f6a9115a5d61f54afbb5e1b1fb5f6017", @@ -55,13 +55,13 @@ "boatstack/migrate_test.go": "b5c2dad2ab762aa202c5c99a8445774bedd982d280ebbb8dd713e7e9f43299d2", "boatstack/next.go": "a4262b2dd310db4e92903ea09cd5f7bd9236cc725341081f6a1a236a46bcb06e", "boatstack/next_test.go": "d158288d66628ab868061f85503663974c0b3cfe3fce0828d8ec5c85ed3ed81c", - "boatstack/plan.go": "4ff1b6bf8b187aa26e4851d30c32496a8e979814a5ce2b4b2a1f1d656f7735d0", + "boatstack/plan.go": "d3bbc962420ea1072d81c41062786577b099614e6bd5ccb75e47c295c506f0bd", "boatstack/plan_test.go": "878dd9086bb583328a7eba1cf45318baeef3d55693be745d5520f07c6ace5e3e", - "boatstack/plan_validation.go": "848f895e323ae8a428e57f57233e068a8d71c2a7c8716d2ff60e60d23188fd1b", - "boatstack/plan_validation_test.go": "4094b5fdbcb89d7a5a16e4a7595ade88a1f02a13df7824d4c37019b8ca01d860", + "boatstack/plan_validation.go": "aaa0cb2123e531160412d6522214fc667e2b2b563dd363bf7fba26adf1208a14", + "boatstack/plan_validation_test.go": "094c0806cdea417565e8e382e7eff1506c767df4df2befba7e8dd73ce9d9f609", "boatstack/planning.go": "4b86ae9dc16393f099ca26812bf3e62909fee42a541b33c33275cc16a80262aa", "boatstack/planning_test.go": "6b156a64182ed76d4c3d392b4c5a26abe5d8b81cea27ee12ac7c4627c827e186", - "boatstack/pr.go": "28b9c7bd41c0cbe3ec8d05787d868db36b424ecd3489678524fd0f4878262d78", + "boatstack/pr.go": "b076ac9e05978b90bf6063209f6ab75bbe2bcd8b9bf38c62ad3ba7b1e2d59e83", "boatstack/pr_test.go": "ae23130d9d96cf214cf272227aa572dd09e2fe3adac22921949f541ba99ecb23", "boatstack/references/artifacts.md": "8f2e79b8af4bd3ad2e32aa3e8c07f10812555d0a3247e4991db75cc1cda395c3", "boatstack/references/config-schema.md": "894c001601246ad87411756902aa7b2962314e4395e2075f94d5c7c93c99e013", @@ -74,7 +74,7 @@ "boatstack/release_test.go": "5cf2d76fe9b836a91ca68eba53d5585e2c4be5b9421aaf939ea0723063a24690", "boatstack/run.go": "fbdbf583c862c41f23d1a200f53d042842db72f19c29fe94e4288a69b0ac4a6b", "boatstack/run_test.go": "34484285fd2457b84faf6d5353117b74af73d4601cd60a96e270b7fd0a7a6a8e", - "boatstack/runtime.go": "60fa6e78d1a7d99a591a9dea3537f3d3a0192ab7b85a798573d5afdc0922f7b4", + "boatstack/runtime.go": "374d32d976716651ac2b1c003735079bd75732284ba9a3315d614917d95a7fa7", "boatstack/runtime_cache.go": "60c4eb0c7dde91d40d6ef3f05adc1a1282d17ff1ca12470d0a008454f7ca7489", "boatstack/runtime_cache_test.go": "b981467ddc9f0f562da6bff5de7a80a9fe5a433a0317541d1e48df268546ac85", "boatstack/safety.go": "7574820a1b3802b59153defb9bf11e2a0ecd3b1f86af13fe4630a99adb740e19", @@ -91,10 +91,10 @@ "docs/account-recovery-walkthrough.md": "676034974594a7d1a559b24dbed31d7ccc429eb81404b203ca07bbdaa19ec3d3", "docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6", "docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79", - "docs/evidence-engineered-coding.md": "b689ca599996074d394a3167a77990fff98d0bd61b686f3485f4803888fac8ed", + "docs/evidence-engineered-coding.md": "c683d2f42e690f5854522c14839dbf0af5a3ea05f807e1c560454dc6ce15054e", "docs/generated-files.md": "136422baf0c7fc2bd5100cfe0ebdb3d9d0705dfd7e7d54bf745dd1037e63492c", "docs/getting-started.md": "eacc814fdffdfa3c7d8052b7cd99a79c04da5c75d88d8b44f3fb68d9afec0316", - "docs/public-claims.json": "822a677480a83525e736bb6c7d978148586efe60e5ea8c045d1077c616cd5d83", + "docs/public-claims.json": "7575107fd494e57112ff4eac3075476dcd74bc47b5f68f8e1501042b2ba913b8", "docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907", "docs/research-and-design.md": "d65c66e323037bda5d45aacef5d48afa6bf93da55901378891d235aca3a5684f", "docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6", @@ -108,7 +108,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": "9d264ba6ab8b7a47bd234e39863861b5fe78e89961b521b9aad3aea379364118", + "labs/diagram-json/plan.lock.json": "d386ffdd63bdeda36f36ad342a01424d8b69c71317f4766e29f43fede85089ef", "labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51", "labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d", "labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed", @@ -155,12 +155,14 @@ "release-notes/2026-07-21-plan-decision-operator.md": "c2a7416ef17a6042583dd60f1f4e847cb1e0f06b28dbde885479efd566bb5cae", "release-notes/2026-07-21-prevent-hallucinated-approver-names.md": "a5fd08bc3d8b983340a2ddd67b71c78b2b34a915fdfe6eb7cdffd0f1d52e3427", "release-notes/2026-07-21-prevent-worktree-dirty-state.md": "d3ebac81a14565461fd7f3c5bd520d881d70b584408ba35a1022cd917c7bf132", - "release-notes/2026-07-21-value-translation-readme.md": "8dd16fd08c1591667a1074fc6825dcbf58beda0faa18ede1526647267418c8ea" + "release-notes/2026-07-21-value-translation-readme.md": "8dd16fd08c1591667a1074fc6825dcbf58beda0faa18ede1526647267418c8ea", + "release-notes/2026-07-22-boundary-analysis-dx.md": "60d727ab3b109fff95a82eb36ee4c6c5833760535b14f386fda349a21b4fe588", + "release-notes/2026-07-22-boundary-oracle-loop.md": "698c2ed7dd0a000e6e210f521989992b8fa476376987819ba92c12feb3528f7c" }, "generator": "operatorstack/intelligence-flow:boatstack-distribution", "schema_version": 1, "source": { - "commit": "e18c8a4e2a77a63476b28f56c84c29289f2b4a47", + "commit": "cb079d704e3b0d82fa88b4318d3fb89fbd96723e", "path": "labs/12-product-engineering-loop", "repository": "operatorstack/intelligence-flow" } diff --git a/boatstack/SKILL.md b/boatstack/SKILL.md index a1d56d4..44c84e2 100644 --- a/boatstack/SKILL.md +++ b/boatstack/SKILL.md @@ -94,15 +94,16 @@ Before starting `/auto-plan` for a new feature, check `next-status --repo . --js 2. Write the bounded outcome definition before proposing architecture. 3. Separate facts, decisions, unknowns, and safely deferrable gaps. 4. Before proposing implementation tasks, inspect the repository and verify any assumptions about API routes, data access, UI components, authentication, server actions, streams, jobs, and external services. Do not guess application architecture. -5. Express verified architectural information as typed `architecture_facts`. Each architecture fact must reference evidence IDs produced by Boatstack repository inspection. Do not create or invent evidence IDs. Reading one arbitrary repository file does not ground an unrelated architectural claim. -6. When an architectural question cannot be verified, record it in `architecture_unknowns`. Do not create an implementation task that depends on an unresolved architecture unknown. Create a bounded discovery task instead. -7. Every architecture-sensitive task must reference the facts it depends on through `requires_facts`. -8. Ask the developer only questions whose answers materially change behavior, contracts, risk, or acceptance. Ask 1-3 concise questions at a time and give each 2-3 mutually exclusive choices with compact inline-code keys (`1a`, `1b`, `1c`, then `2a`, `2b`, and so on). Suffix exactly one choice per question with `(Recommended)`, explain the impact, and end with one reply hint naming the keys or `r` for all recommendations. Use this format with structured question tools and plain text alike, then return `WAITING_FOR_INPUT`. -9. Treat a standalone `r` as explicit human acceptance only when every displayed question has exactly one recommendation. Echo the selected question-to-answer mapping before recording each as `ANSWERED`; otherwise ask again without choosing. An authoritative repository fact is `DISCOVERED`, an agent suggestion or inferred choice is `PROPOSED`, and only an explicit human response is `ANSWERED`. Every material proposal remains in `plan.md` as a `blocking_questions` ID until the human answers it. Never use labels such as “answered by plan default.” -10. Create the feature spec: problem, users, outcomes, non-goals, acceptance criteria, invariants, interfaces, failure behavior, observability, rollout, and rollback. Translate every accepted claim into an observable condition with a defensible oracle. -11. Run product, design, engineering, and developer-experience reviews only when applicable. If gstack is installed, its review skills can implement these lenses; do not require it. -12. 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. -13. 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`. +5. If `workflow.boundary_analysis` is `true` in `project.json`: Evaluate if the requested change is a symptom of a missing systemic boundary (e.g., deficient data normalization, leaky validation, missing authorization edge). If it is, perform a rapid codebase scan for other vulnerabilities sharing this failure mode. Present this as a material product decision, showing concrete codebase evidence of the blast radius. Offer tiered implementation paths: [1a] Symptom Patch (fix only the requested route), or [1b] Programmatic Enforcement (refactor the edge and install a programmatic boundary to mathematically prevent this). If the user chooses programmatic enforcement, explicitly structure the plan into two delivery slices: Slice 1 establishes the programmatic boundary (hook, trigger, or strict test), and Slice 2 implements the feature using that boundary. +6. Express verified architectural information as typed `architecture_facts`. Each architecture fact must reference evidence IDs produced by Boatstack repository inspection. Do not create or invent evidence IDs. Reading one arbitrary repository file does not ground an unrelated architectural claim. +7. When an architectural question cannot be verified, record it in `architecture_unknowns`. Do not create an implementation task that depends on an unresolved architecture unknown. Create a bounded discovery task instead. +8. Every architecture-sensitive task must reference the facts it depends on through `requires_facts`. +9. Ask the developer only questions whose answers materially change behavior, contracts, risk, or acceptance. Ask 1-3 concise questions at a time and give each 2-3 mutually exclusive choices with compact inline-code keys (`1a`, `1b`, `1c`, then `2a`, `2b`, and so on). Suffix exactly one choice per question with `(Recommended)`, explain the impact, and end with one reply hint naming the keys or `r` for all recommendations. Use this format with structured question tools and plain text alike, then return `WAITING_FOR_INPUT`. +10. Treat a standalone `r` as explicit human acceptance only when every displayed question has exactly one recommendation. Echo the selected question-to-answer mapping before recording each as `ANSWERED`; otherwise ask again without choosing. An authoritative repository fact is `DISCOVERED`, an agent suggestion or inferred choice is `PROPOSED`, and only an explicit human response is `ANSWERED`. Every material proposal remains in `plan.md` as a `blocking_questions` ID until the human answers it. Never use labels such as “answered by plan default.” +11. Create the feature spec: problem, users, outcomes, non-goals, acceptance criteria, invariants, interfaces, failure behavior, observability, rollout, and rollback. Translate every accepted claim into an observable condition with a defensible oracle. +12. Run product, design, engineering, and developer-experience reviews only when applicable. If gstack is installed, its review skills can implement these lenses; do not require it. +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 /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 --artifact ` on stdin. 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. diff --git a/boatstack/export.go b/boatstack/export.go index c01852b..2ad0580 100644 --- a/boatstack/export.go +++ b/boatstack/export.go @@ -170,7 +170,7 @@ Run the %s operation from @.product-loop/workflow.md. %s -Read @.product-loop/project.json, @.product-loop/artifacts.md, and only the minimal repository context relevant to the current feature. %s +Read @.product-loop/project.json, @.product-loop/artifacts.md, @.product-loop/verified-boundaries.md (if it exists), and only the minimal repository context relevant to the current feature. Do not propose or write code that violates established repository boundaries. %s Use the gate semantics in the canonical workflow. Do not redefine them in this adapter. Auto-plan and plan-gate may create or update Markdown only. Classify authoritative repository facts as DISCOVERED, agent suggestions as PROPOSED, and only explicit human responses as ANSWERED. Every material proposal remains in blocking_questions; never label an agent default as answered. For 1-3 finite questions, use compact keys such as 1a/1b and 2a/2b, suffix exactly one choice per question with (Recommended), and offer r to accept all displayed recommendations. Treat r as explicit human acceptance only when every displayed question has exactly one recommendation; echo the selected mapping before recording the answers. Use the same format with structured question tools or plain text and return WAITING_FOR_INPUT internally. Never silently choose a default. Boatstack leaves implementation tactics open, but completion, approval, and shipping claims require current evidence. During managed delivery, read the active delivery slice, never push or mutate a PR directly, and require slice-scoped test and review receipts before ship-gate. A successful publication activates the next declared slice; parent-plan approval never skips its gates. @@ -264,11 +264,11 @@ func BuildExportBundle(configPath string, config ProjectConfig, rawConfig []byte operations := map[string]string{ "boatstack-next": "Run the project-local helper next-status --repo . --json. This operation is strictly read-only: do not run the reported operation, edit artifacts, contact GitHub, or advance a gate. Translate the structured result into the canonical response contract. Show the verified feature and active slice when present. Distinguish NOT_STARTED and SOURCE_PLAN_READY, whose next operation is auto-plan, from FEATURE_COMPLETE, which responds Feature complete and requires no action. If verification_status is BLOCKED, name the ambiguity or invalid evidence and make its safe restoration the one action; never clear artifacts. Conversation, terminal, worktree, or process observations may be included as clearly labeled context only and must never override the repository-backed result. Otherwise make the returned next_operation the one next action.", "boatstack-run": "First run the read-only next-status --repo . --json. If SOURCE_PLAN_READY, execute auto-plan without Git preflight and pause at its normal decision or approval boundary. If NOT_STARTED, respond Start a Boatstack feature and ask the user to save exactly one host Plan-mode file, then run /auto-plan; do not fetch or require a feature branch. If FEATURE_COMPLETE, respond Feature complete with No action required without requiring a remote or fetching. Stop on UNVERIFIED, BLOCKED, ambiguous, stale, or invalid state. Before executing the first delivery-stage next_operation (build, repair, test-gate, review-gate, or ship-gate), run the project-local helper run-preflight --repo . --json; planning and plan-gate do not require it. Stop on a blocked preflight; never merge, rebase, force-push, discard changes, switch branches, or create a constrained delivery branch to repair freshness. Then execute exactly the verified next_operation using the canonical operation semantics, verify the resulting repository state, and resolve again. Continue across every declared delivery slice. Pause for the exact plan approval reply a, any material product decision, and the exact PR publication reply o or u; after a valid reply in the current host session, automatically continue the run. A run request never supplies approval or publication authority. For a same-intent test or review failure, use repair, record the observation, and retry from the returned stage, up to three complete automated repair-and-gate cycles for the active slice in this invocation. Stop immediately on an amendment, ambiguity, unsafe or destructive capability, stale evidence, branch mismatch, unsupported recovery, or exhausted repair budget. If Cursor reports MainThreadShellExec not initialized, explain that Cursor failed before the Boatstack hook started and make Developer: Reload Window the one recovery action; do not recommend reinstall unless Boatstack reports a missing, drifted, unsafe, or checksum-invalid runtime. Do not use conversation as workflow evidence and do not create durable autopilot state. Report the feature, active slice, stages completed during this invocation, completion or pause reason, repair-cycle count, and exactly one next action. Ship means publishing every declared slice PR for review; never merge or deploy.", - "auto-plan": "Discover exactly one saved Plan-mode file and refine it into a Markdown-only draft feature package whose canonical structured artifact is plan.md. Run check-plan read-only. Record affected_paths and structured side_effects for external writes; use an immutable target identity, transactional or fix-forward recovery, and destructive=false. When workflow.maintain_changelog is true, include CHANGELOG.md in every delivery slice's affected paths. Keep internal phases as tasks in one delivery slice. Only when the accepted outcome explicitly needs multiple PRs, declare ordered delivery_slices and assign every task exactly once; plan approval never authorizes publication. Do not implement, create JSON or locks, or imply acceptance. If ready, respond with Plan ready and make Run /plan-gate the one next action. If decisions remain, respond with I need your input and ask only 1-3 material questions.", + "auto-plan": "Discover exactly one saved Plan-mode file and refine it into a Markdown-only draft feature package whose canonical structured artifact is plan.md. Run check-plan read-only. If workflow.boundary_analysis is true, evaluate if the change is a symptom of a missing systemic boundary and perform a rapid codebase scan for other vulnerabilities. Present this as a material product decision with tiered paths: [1a] Symptom Patch or [1b] Programmatic Enforcement (Slice 1 for the boundary, Slice 2 for the feature). Record affected_paths and structured side_effects for external writes; use an immutable target identity, transactional or fix-forward recovery, and destructive=false. When workflow.maintain_changelog is true, include CHANGELOG.md in every delivery slice's affected paths. Keep internal phases as tasks in one delivery slice. Only when the accepted outcome explicitly needs multiple PRs, declare ordered delivery_slices and assign every task exactly once; plan approval never authorizes publication. Do not implement, create JSON or locks, or imply acceptance. If ready, respond with Plan ready and make Run /plan-gate the one next action. If decisions remain, respond with I need your input and ask only 1-3 material questions.", "plan-gate": "Run check-plan read-only, present its fingerprint and all open decisions, and require explicit human approval. While plan approval is pending, the normal user action is the exact standalone reply a. Trim surrounding whitespace and match a case-insensitively; do not treat [a] or an a embedded in other text as approval. Continue accepting the full reply approve for compatibility, but do not advertise it in the user-facing response. Resolve approved_by from an explicit supplied identity, otherwise from the authenticated GitHub login when available; ask one short identity follow-up only when neither exists, and never invent a placeholder name (e.g., Sam, Eve) and never infer it from a filesystem username, commit history, or agent identity. On approval invoke record-approval with the resolved human, RFC3339 timestamp, and exact displayed fingerprint so it writes only approval.md. While pending, respond Ready for your approval and render the one next action as: Reply `a` to approve. After recording, respond Approved — ready to build and make entering the host execution mode and running /build the one next action. Remain in Plan mode; do not compile or request an early mode switch.", "build": "First confirm the host is in an execution-capable mode. If the mode transition is rejected or product-code writes remain unavailable, return READY_FOR_BUILD internally without activating the plan, compiling JSON, or writing a lock. Only then locate plan.md and approval.md and run activate-plan before the first product-code edit. Stop if it reports BLOCKED. Read delivery-status and implement only the active delivery slice task_ids. When workflow.maintain_changelog is true, add a concise entry grounded in the active slice's actual changes under the current CHANGELOG.md Unreleased heading before recording test evidence. Use only the one allowed category needed by the entry and do not add empty category headings. If the file is absent, create the documented minimal skeleton with ## [Unreleased] - YYYY-MM-DD and the first categorized entry; if it exists, add to the current file without rewriting its history or layout. Run the internal repository safety check after operational or high-risk edits; a destructive capability blocks execution and gate progression but does not block reviewable source editing. Implementation tactics remain open inside the approved boundary, but push and PR mutation are never build tactics and are denied while managed delivery is active. On success respond Build complete and make Run /test-gate the one next action. When a new product decision blocks work, respond Build needs a decision and ask only that question.", "repair": "First run next-status --repo . --json. Repair requires an active managed delivery and the user's exact free-form requested change. If NOT_STARTED or SOURCE_PLAN_READY, respond No active delivery to repair and make /auto-plan the one next action; do not ask for repair details. If DRAFT_PLAN or APPROVED, route to the returned plan-gate or build operation because no managed delivery exists yet. If FEATURE_COMPLETE and the user supplied an exact correction, preserve the published evidence and plan a linked Boatstack feature with parent_delivery set to the completed feature; otherwise ask for the exact correction. Stop on BLOCKED or INVALID_STATE and preserve all artifacts. For an active delivery, read delivery-status, the current plan lock and acceptance criteria, the actual diff, and current receipts. Compare the exact request with approved intent. Classify it as implementation_repair, verification_repair, review_repair, requirement_amendment, or needs_clarification, then invoke record-change before any product edit. Same-intent repairs may proceed at the returned RESUME_STAGE; requirement amendments and ambiguous intent must stop for a concise plan amendment or one clarifying question. Never edit changes.md or managed delivery state directly. After a repair, reuse the existing /test-gate and /review-gate; do not invent repair-specific gates. If Cursor reports MainThreadShellExec not initialized, make Developer: Reload Window the one recovery action because Boatstack's hook did not start; reserve reinstall guidance for Boatstack runtime integrity errors.", - "test-gate": "Read delivery-status and test only the active delivery slice. Run the internal repository safety check, build a requirement-to-evidence matrix, and treat self-authored tests as evidence rather than the sole oracle. External writes require immutable target identity, transactional or fix-forward failure behavior, and an independent safety oracle. Commit the intentional slice product and evidence diff, then record-delivery-gate for the active feature and slice with --gate test and PASS or PASS_WITH_GAPS. Editing evidence Markdown alone never passes the gate. On pass respond Tests passed and make Run /review-gate the one next action. On failure respond Testing found a problem and make the required non-destructive repair the one next action.", + "test-gate": "Read delivery-status and test only the active delivery slice. Run the internal repository safety check, build a requirement-to-evidence matrix, and treat self-authored tests as evidence rather than the sole oracle. If the active slice contains a systemic_boundary task, the evidence must prove the verification_oracle actively blocked or normalized a violation attempt (negative test). External writes require immutable target identity, transactional or fix-forward failure behavior, and an independent safety oracle. Commit the intentional slice product and evidence diff, then record-delivery-gate for the active feature and slice with --gate test and PASS or PASS_WITH_GAPS. Editing evidence Markdown alone never passes the gate. On pass respond Tests passed and make Run /review-gate the one next action. On failure respond Testing found a problem and make the required non-destructive repair the one next action.", "review-gate": "Read delivery-status and review the active slice's actual diff against approved intent, invariants, risks, gaps, and test evidence. Run the internal repository safety check. Executable destructive capability is blocking even when ordinary tests pass. When workflow.maintain_changelog is true, verify the new CHANGELOG.md Unreleased entry accurately describes the actual reader-visible impact rather than commits, PR metadata, artifacts, or test commands. On pass invoke record-delivery-gate for the same feature and slice with --gate review; it must reject a changed or untested diff and a missing or malformed required changelog entry. Then respond Review passed and make Run /ship-gate the one next action. When blocked respond Changes required and make the highest-priority blocking repair the one next action.", "ship-gate": "Prepare a reviewer-ready PR only; do not merge or deploy without separate authorization. Require the current managed feature approval, lock, test evidence, review evidence, and a passing repository safety scan, and commit the intentional product/artifact diff before projection. Internally run pr-context --repo . --feature in json and template formats, project the approved intent, actual committed diff, decisions, evidence, gaps, rollout, rollback, safety outcome, and operator-only recovery boundary into its required pr.md path, then run check-pr --repo . --preview . Generate a clear, product-focused PR title that describes the user value or system outcome rather than listing technical components (do not use sequence prefixes like 'PR 1'). Always include why, what changed, review order, evidence, gaps/risks, rollout/rollback, and collapsed provenance; add UI evidence, security/privacy, migration, or operations sections only when the diff makes them relevant. Show the exact title and rendered body before any GitHub mutation. If PR_ACTION is open, respond PR ready and render the one next action as: Reply `o` to open PR. If update, render: Reply `u` to update PR. If manual, preserve the preview and give one manual publication action. Continue accepting the full replies open PR and update PR for compatibility without advertising them. Only after the matching state-scoped shortcut or compatible full reply: commit only the reviewed pr.md, rerun check-pr and require the same preview fingerprint (PREVIEW_FINGERPRINT), then run publish-pr with --action open or update and that fingerprint. The publisher performs a non-force push and rechecks context before GitHub mutation. If the diff or evidence changes, regenerate instead. If a required check fails on the base branch too, record the evidence and recommend a separate repair PR. Never edit unrelated code in this approved feature branch; a policy-approved bypass requires explicit human authorization. After publication respond PR opened with the link and make Review the PR the one next action; never imply merge authorization. If publish-pr returns UPDATE_AVAILABLE, keep Review the PR as the only next action and append a collapsed update notice saying no files changed and /boatstack-update may be run from the clean default branch after this feature PR merges. Do not check for releases before successful publication.", "boatstack-update": "Prepare a visible Boatstack infrastructure update; never mix it into product work or merge it. First run the current helper doctor and force check-update. If current, respond Boatstack is current with No action required. Before mutation fetch the default ref, then require the current clean default branch whose HEAD equals origin/; otherwise respond Update postponed and make finishing the current feature, switching to the clean default branch, and rerunning /boatstack-update the one action. Ensure no update PR or branch already exists, create chore/update-boatstack-v, then run the installer fetched from that exact release tag with BOATSTACK_MODE=update, BOATSTACK_VERSION=, BOATSTACK_REPO=, and BOATSTACK_YES=1. Use install.sh on macOS/Linux and install.ps1 on Windows. The verified update must preserve configuration, adapters, integrations, and user-owned host settings, run doctor, and touch only Boatstack infrastructure. Show the version transition, release notes and link, integration state, exact diff, changed paths, checksums, rollout, and rollback. Respond Boatstack update ready and render the one next action as: Reply `o` to open update PR. Continue accepting the full reply open update PR for compatibility without advertising it. Only the matching state-scoped shortcut or compatible full reply authorizes staging the installer-reported paths, committing chore: update Boatstack to , normal push, and opening a reviewer-ready update PR. If GitHub auth is unavailable, preserve the branch and give one manual publication action. After publication respond Update PR opened with the link and make Review the PR the one next action. On one collision or health failure, respond Update needs attention and make addressing that named problem the one next action. Never merge automatically.", diff --git a/boatstack/plan.go b/boatstack/plan.go index ad31244..9a62ffa 100644 --- a/boatstack/plan.go +++ b/boatstack/plan.go @@ -413,6 +413,10 @@ func ValidatePlan(plan map[string]any, opts *ValidatePlanOptions) error { } } + if err := validateSystemicBoundaries(plan); err != nil { + return err + } + if stringValue(plan["feature_id"]) == "" { return fmt.Errorf("feature_id is required") } diff --git a/boatstack/plan_validation.go b/boatstack/plan_validation.go index cbce636..714a283 100644 --- a/boatstack/plan_validation.go +++ b/boatstack/plan_validation.go @@ -129,5 +129,28 @@ func validateArchitectureGrounding(plan map[string]any, opts *ValidatePlanOption } } + return nil +} + +func validateSystemicBoundaries(plan map[string]any) error { + boundaries, ok := objectSlice(plan["systemic_boundaries"]) + if !ok || len(boundaries) == 0 { + return nil + } + + slices, ok := objectSlice(plan["delivery_slices"]) + if !ok || len(slices) < 2 { + return fmt.Errorf("Programmatic enforcement requires a minimum of 2 delivery_slices (Boundary -> Feature)") + } + + for _, boundary := range boundaries { + id := stringValue(boundary["id"]) + if id == "" { + return fmt.Errorf("systemic boundary requires an id") + } + if stringValue(boundary["verification_oracle"]) == "" { + return fmt.Errorf("systemic boundary %s requires a verification_oracle", id) + } + } return nil } \ No newline at end of file diff --git a/boatstack/plan_validation_test.go b/boatstack/plan_validation_test.go index e9cdf02..e99b5a6 100644 --- a/boatstack/plan_validation_test.go +++ b/boatstack/plan_validation_test.go @@ -121,3 +121,56 @@ func TestPLAN_INVALIDExitsRepair(t *testing.T) { t.Fatalf("expected plan_invalid to map to AUTO_PLAN, got %v", resume) } } + +func TestValidateSystemicBoundaries(t *testing.T) { + plan := validV2Plan() + + // Valid configuration + plan["systemic_boundaries"] = []any{ + map[string]any{ + "id": "bnd_1", + "verification_oracle": "Negative test confirming boundary blocks invalid input", + }, + } + plan["delivery_slices"] = []any{ + map[string]any{"id": "slice_1", "task_ids": []any{"task_1"}}, + map[string]any{"id": "slice_2", "task_ids": []any{"task_2"}}, + } + if err := validateSystemicBoundaries(plan); err != nil { + t.Fatalf("expected valid systemic boundaries, got: %v", err) + } + + // Missing oracle + plan["systemic_boundaries"] = []any{ + map[string]any{ + "id": "bnd_1", + }, + } + if err := validateSystemicBoundaries(plan); err == nil || !strings.Contains(err.Error(), "requires a verification_oracle") { + t.Fatalf("expected error for missing oracle, got: %v", err) + } + + // Missing ID + plan["systemic_boundaries"] = []any{ + map[string]any{ + "verification_oracle": "Negative test", + }, + } + if err := validateSystemicBoundaries(plan); err == nil || !strings.Contains(err.Error(), "requires an id") { + t.Fatalf("expected error for missing id, got: %v", err) + } + + // Missing multiple slices + plan["systemic_boundaries"] = []any{ + map[string]any{ + "id": "bnd_1", + "verification_oracle": "Negative test", + }, + } + plan["delivery_slices"] = []any{ + map[string]any{"id": "slice_1", "task_ids": []any{"task_1"}}, + } + if err := validateSystemicBoundaries(plan); err == nil || !strings.Contains(err.Error(), "requires a minimum of 2 delivery_slices") { + t.Fatalf("expected error for insufficient slices, got: %v", err) + } +} diff --git a/boatstack/pr.go b/boatstack/pr.go index 296e639..06e7de2 100644 --- a/boatstack/pr.go +++ b/boatstack/pr.go @@ -842,6 +842,9 @@ func PublishPR(options PRPublishOptions) (string, error) { if err := MarkDeliveryPublished(repo, context.Feature, context.SliceID, strings.TrimSpace(url)); err != nil { return "", fmt.Errorf("PR opened but delivery state could not advance: %w", err) } + if err := extractSystemicBoundaries(repo, context.Feature); err != nil { + fmt.Fprintf(os.Stderr, "WARNING: could not extract systemic boundaries: %v\n", err) + } } return strings.TrimSpace(url), nil } @@ -852,10 +855,46 @@ func PublishPR(options PRPublishOptions) (string, error) { if err := MarkDeliveryPublished(repo, context.Feature, context.SliceID, existingURL); err != nil { return "", fmt.Errorf("PR updated but delivery state could not advance: %w", err) } + if err := extractSystemicBoundaries(repo, context.Feature); err != nil { + fmt.Fprintf(os.Stderr, "WARNING: could not extract systemic boundaries: %v\n", err) + } } return existingURL, nil } +func extractSystemicBoundaries(repo, feature string) error { + lockPath := filepath.Join(repo, ".product-loop", "features", feature, "plan.lock.json") + value, err := os.ReadFile(lockPath) + if err != nil { + return nil // if it doesn't exist, ignore + } + var lock map[string]any + if err := json.Unmarshal(value, &lock); err != nil { + return err + } + boundaries, ok := lock["systemic_boundaries"].([]any) + if !ok || len(boundaries) == 0 { + return nil + } + outPath := filepath.Join(repo, ".product-loop", "verified-boundaries.md") + f, err := os.OpenFile(outPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) + if err != nil { + return err + } + defer f.Close() + + for _, b := range boundaries { + boundary, _ := b.(map[string]any) + id := stringValue(boundary["id"]) + failureMode := stringValue(boundary["failure_mode"]) + enforcement := stringValue(boundary["enforcement_mechanism"]) + if id != "" && failureMode != "" && enforcement != "" { + fmt.Fprintf(f, "- **%s**: Prevents `%s` using `%s`\n", id, failureMode, enforcement) + } + } + return nil +} + func PRPreviewTemplate(context PRContext) string { quote := func(value string) string { encoded, _ := json.Marshal(value) diff --git a/boatstack/runtime.go b/boatstack/runtime.go index 2716ae0..cc4b558 100644 --- a/boatstack/runtime.go +++ b/boatstack/runtime.go @@ -51,6 +51,7 @@ type Workflow struct { IndependentReviewForHighRisk bool `json:"independent_review_for_high_risk"` AllowPassWithGaps bool `json:"allow_pass_with_gaps"` MaintainChangelog bool `json:"maintain_changelog"` + BoundaryAnalysis bool `json:"boundary_analysis,omitempty"` } type IntegrationState struct { diff --git a/docs/evidence-engineered-coding.md b/docs/evidence-engineered-coding.md index c1d0957..a5d4941 100644 --- a/docs/evidence-engineered-coding.md +++ b/docs/evidence-engineered-coding.md @@ -146,6 +146,6 @@ Delivery and system improvement also remain separate. A failed task may suggest ## What is evidence-backed -The current moves were derived from the Intelligence Flow benchmark corpus and product-repository studies. The generated source commit is [`e18c8a4e2a77a63476b28f56c84c29289f2b4a47`](https://github.com/operatorstack/intelligence-flow/tree/e18c8a4e2a77a63476b28f56c84c29289f2b4a47/labs/12-product-engineering-loop). +The current moves were derived from the Intelligence Flow benchmark corpus and product-repository studies. The generated source commit is [`cb079d704e3b0d82fa88b4318d3fb89fbd96723e`](https://github.com/operatorstack/intelligence-flow/tree/cb079d704e3b0d82fa88b4318d3fb89fbd96723e/labs/12-product-engineering-loop). The evidence supports specific failure mechanisms and guardrails. It does not establish that Boatstack is optimal, that control-theory notation proves software quality, or that one workflow dominates every team. Those are evaluation questions, so the distribution preserves measurements, provenance, gaps, and negative results. diff --git a/docs/public-claims.json b/docs/public-claims.json index a2a2659..99ce110 100644 --- a/docs/public-claims.json +++ b/docs/public-claims.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "source_commit": "e18c8a4e2a77a63476b28f56c84c29289f2b4a47", + "source_commit": "cb079d704e3b0d82fa88b4318d3fb89fbd96723e", "statuses": ["verified", "observed", "still_being_evaluated"], "claims": [ { @@ -12,7 +12,7 @@ "readable_evidence": "why-these-steps.md#portable-workflow-and-state", "implementation": ["../boatstack/export.go", "../boatstack/references/artifacts.md", "../boatstack/references/workflow.md"], "verification": ["../boatstack/export_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "human-decisions", @@ -23,7 +23,7 @@ "readable_evidence": "why-these-steps.md#human-decisions", "implementation": ["../boatstack/references/workflow.md", "../boatstack/plan.go"], "verification": ["../boatstack/plan_test.go", "../boatstack/planning_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "validation-provenance", @@ -34,7 +34,7 @@ "readable_evidence": "why-these-steps.md#validation-provenance", "implementation": ["validation-and-evidence.md", "../boatstack/plan.go"], "verification": ["../boatstack/plan_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "irreversible-operations", @@ -46,7 +46,7 @@ "readable_evidence": "why-these-steps.md#irreversible-operations", "implementation": ["safety.md", "../boatstack/safety.go", "../boatstack/hooks.go"], "verification": ["../boatstack/safety_test.go", "../boatstack/hooks_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "reviewer-ready-pr", @@ -57,7 +57,7 @@ "readable_evidence": "why-these-steps.md#reviewer-ready-pr", "implementation": ["../boatstack/pr.go", "getting-started.md"], "verification": ["../boatstack/pr_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "phase-scoped-delivery", @@ -68,7 +68,7 @@ "readable_evidence": "why-these-steps.md#phase-scoped-delivery", "implementation": ["../boatstack/delivery.go", "../boatstack/safety.go", "../boatstack/hooks.go", "../boatstack/references/workflow.md"], "verification": ["../boatstack/delivery_test.go", "../boatstack/pr_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "model-neutral-contract", @@ -79,7 +79,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md", "../boatstack/references/workflow.md"], "verification": ["../boatstack/export_test.go", "../boatstack/planning_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "cross-model-failures", @@ -90,7 +90,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md"], "verification": ["benchmark-corpus-audit.md", "benchmark-submission-audit.md"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "lower-cost-outcomes", @@ -101,7 +101,7 @@ "readable_evidence": "why-these-steps.md#model-choice-and-budget", "implementation": ["research-and-design.md"], "verification": ["benchmark-corpus-audit.md", "benchmark-submission-audit.md"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "git-worktree-activation", @@ -112,7 +112,7 @@ "readable_evidence": "why-these-steps.md#git-worktree-activation", "implementation": ["../boatstack/runtime_cache.go", "../boatstack/hooks.go"], "verification": ["../boatstack/runtime_cache_test.go", "../boatstack/hooks_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" }, { "id": "visible-updates", @@ -123,7 +123,7 @@ "readable_evidence": "why-these-steps.md#visible-updates", "implementation": ["../boatstack/update.go", "../boatstack/init.go"], "verification": ["../boatstack/update_test.go", "../boatstack/init_test.go", "../boatstack/export_test.go"], - "last_verified_version": "source:e18c8a4e2a77a63476b28f56c84c29289f2b4a47" + "last_verified_version": "source:cb079d704e3b0d82fa88b4318d3fb89fbd96723e" } ] } diff --git a/labs/diagram-json/plan.lock.json b/labs/diagram-json/plan.lock.json index 7a8e68f..8891c8b 100644 --- a/labs/diagram-json/plan.lock.json +++ b/labs/diagram-json/plan.lock.json @@ -6,7 +6,7 @@ "plan_path": "labs/diagram-json/plan.md", "plan_sha256": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51", "schema_version": 1, - "source_commit": "e18c8a4e2a77a63476b28f56c84c29289f2b4a47", + "source_commit": "cb079d704e3b0d82fa88b4318d3fb89fbd96723e", "source_plan_path": "labs/diagram-json/source-plan.md", "source_plan_sha256": "e10593ddaa7522ab80cc991d0a09399257139799e37f737794cd49d68a39985b", "spec_path": "labs/diagram-json/spec.md", diff --git a/release-notes/2026-07-22-boundary-analysis-dx.md b/release-notes/2026-07-22-boundary-analysis-dx.md new file mode 100644 index 0000000..ad7f9dc --- /dev/null +++ b/release-notes/2026-07-22-boundary-analysis-dx.md @@ -0,0 +1,3 @@ +### Boundary Failure Mode Analysis in Auto-Plan + +Introduced an opt-in `boundary_analysis` configuration to `.boatstack-project.json`. When enabled, the `auto-plan` operation actively analyzes requested changes to determine if they are symptoms of missing systemic boundaries (e.g., deficient data normalization or leaky validation). Instead of silently expanding scope, Boatstack presents this as a material product decision with concrete codebase evidence and offers tiered implementation paths: a local symptom patch or a programmatic enforcement lock. If programmatic enforcement is selected, the plan is explicitly split into two delivery slices, ensuring the boundary (hook, trigger, or strict test) is established before the feature is implemented. diff --git a/release-notes/2026-07-22-boundary-oracle-loop.md b/release-notes/2026-07-22-boundary-oracle-loop.md new file mode 100644 index 0000000..74039a3 --- /dev/null +++ b/release-notes/2026-07-22-boundary-oracle-loop.md @@ -0,0 +1,7 @@ +### Deterministic enforcement of Boundary-Oracle Loop + +Transformed the Boundary Failure Mode Analysis from a prompt suggestion into a strict, programmatic intelligence harness: +1. **Schema Contract:** Added `systemic_boundaries` array to the `plan.md` schema, requiring each boundary to define a `verification_oracle`. +2. **Structural Lock:** Updated `ValidatePlan` to physically reject plans that define a systemic boundary but fail to provide an oracle or isolate the boundary into its own delivery slice. +3. **Execution Lock:** Updated `/test-gate` instructions to require test evidence proving that the verification oracle (negative test) successfully blocks or normalizes a violation attempt. +4. **Compounding Memory:** Upon PR publication (`publish-pr`), Boatstack now extracts verified `systemic_boundaries` from the feature lock and appends them to `.product-loop/verified-boundaries.md`. Agent system prompts have been updated to read this file and natively respect established boundaries in future runs.