From 625976c9242839ae90e8f6738ff9ff4a3f1b58e5 Mon Sep 17 00:00:00 2001 From: "operator-stack-publisher[bot]" Date: Thu, 23 Jul 2026 16:48:01 +0000 Subject: [PATCH] Sync Boatstack from Intelligence Flow Labs @ c9e110ae06ef --- CONTRIBUTING.md | 2 +- UPSTREAM.json | 16 ++-- boatstack/AGENTS.md | 62 ++++++++++++ boatstack/pr.go | 26 ++++- boatstack/pr_test.go | 96 ++++++++++++++++++- docs/evidence-engineered-coding.md | 2 +- docs/public-claims.json | 24 ++--- labs/diagram-json/plan.lock.json | 2 +- ...2026-07-23-managed-pr-task-graph-layout.md | 5 + 9 files changed, 207 insertions(+), 28 deletions(-) create mode 100644 boatstack/AGENTS.md create mode 100644 release-notes/2026-07-23-managed-pr-task-graph-layout.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2287a1..35a72f8 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/c288814c89139fa36e7b914ce14d9917f12d32d0/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/c9e110ae06ef139d8ae336262558bc8bf21a1e2a/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 2993200..84c3b59 100644 --- a/UPSTREAM.json +++ b/UPSTREAM.json @@ -12,11 +12,12 @@ }, "files": { ".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957", - "CONTRIBUTING.md": "47f98fbd40e12646c9314b53ce5a1b297cfd154bae919b5751bf93db28557bd0", + "CONTRIBUTING.md": "66d71c53812017e686d180a310b71f058664a081be8f05c38299e429581b5c64", "README.md": "125b47671a68556df382f19756fb61fa18925606cbbaf54d6bc9df8872b36870", "assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63", "assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5", "assets/boatstack-portability.svg": "66dfdfa85db857b3bd18b32047a6975f1fbbfc4dc091158e8277193f9969a346", + "boatstack/AGENTS.md": "8694b4f13fb8b0553ea065a5bb0fa216aefc69389dfc0e7ad7703d8b81baff4d", "boatstack/BUG-worktree-delivery-state.md": "02469cf51c3849dad5743783e248e5c04583e4240507fbef0e3f890cd6a95724", "boatstack/SKILL.md": "7c7b3568d836cb176c92762a8315fa834cd61a531a629c97a5cd98d6f7689be0", "boatstack/agents/gemini.yaml": "cbf43b387399e456fa6178f86d83e6e35567e6142ff800f8de6ffca306fa963e", @@ -69,8 +70,8 @@ "boatstack/plan_validation_test.go": "6cbde4ac719baef6b73aa569515d6a9daadcbf14b33f76fa78159826954e20fa", "boatstack/planning.go": "ef4507a9fecc900f0691372c50883f328c9232c3dfd6986fbde26fb7ef436ae3", "boatstack/planning_test.go": "c105a9c78c342be06614bf54d0bc1b661b0f7af64d63b79e43bd1fcc2769edd5", - "boatstack/pr.go": "d277d03008f0af2443d754998784a6e8d9540298294658b578565ff7d8fd354a", - "boatstack/pr_test.go": "838e6c244aed84317d00e6f49de6b65bb08f6fe1e1a11fb37aad8428ae2f6ea1", + "boatstack/pr.go": "bdb066acb329b6b772cb880db2e590b381cae909f270085cfacb8ef2fbfda651", + "boatstack/pr_test.go": "7f82954d94c1ceae848a581dda25e58af92251d78a5a94ed2d672bedf5a0349e", "boatstack/recovery.go": "dd816b18b54a0085b8d8276a93ee98d2b1e90099059a0d85cf6e24edf6f37d5b", "boatstack/recovery_test.go": "29490e7477ba602491330036a491289dd9117b99ff862f66dae421ba17e04c9f", "boatstack/references/artifacts.md": "5fa888ac519085d65cee1d04df5902761651bcf2d7af81711fa0f8ecd1fc0f59", @@ -108,10 +109,10 @@ "docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6", "docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79", "docs/configuration.md": "4d8f207b415a5a1e3b9b1698ee7bb1221aa0e5496a061bb8054294df2f347ad1", - "docs/evidence-engineered-coding.md": "295e908297c7a1c63d9e4784e7f5a5299ab6f515f9e6364f825b2a2b8fa3688d", + "docs/evidence-engineered-coding.md": "4b7b413d909b936853b0db3fe13af84a53d5ade5a62ad4bdbbfac5189a53f700", "docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3", "docs/getting-started.md": "f314270c5ed1a55bbef5f3ddbcb5596693dbee9374e5f0d3df8838cefbd68052", - "docs/public-claims.json": "dff1654cb0901c026770f0358918b29e11a5836a6fbc8668f7449b10ee208e53", + "docs/public-claims.json": "e57651659291d0d78ab9e62cfdfcc91d9e1d8692d044a626b7a55e1b5f77b258", "docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907", "docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6", "docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6", @@ -125,7 +126,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": "100ee5d8381c04b3f11b4ffe3462a214883b85ddb1df73beb88a61251952cd41", + "labs/diagram-json/plan.lock.json": "49b9accb7a855c021b7f0bc62d283f242e0a566923d0a2f430e5dafaf76d13f4", "labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51", "labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d", "labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed", @@ -187,13 +188,14 @@ "release-notes/2026-07-23-canonical-update-ownership.md": "7f34f890b252493797519389b23f1b56ec7ec16db7547aac8ea196f75f3b8c2c", "release-notes/2026-07-23-explicit-source-plan.md": "ec1f97434f9263f6db4bc3b83ae83213053cd2bc6b7465e4fb2d67cbea5cf731", "release-notes/2026-07-23-ignore-ambiguous-deliveries.md": "9b1b9fd48db340b91fcced1c282297de0ecad8744723f2b1fdd94033927a88c4", + "release-notes/2026-07-23-managed-pr-task-graph-layout.md": "e2d67f15cc6a1eb200d6f13f81d891b30eae1bd51182d768dda561fcfdc69435", "release-notes/2026-07-23-recoverable-repository-sync.md": "3afc4f6220ae76df3bd6dcd15fc180135274c808729e9c512a2c53462ec690c2", "release-notes/2026-07-23-shipped-feature-candidate-resolution.md": "bd8ee8e7f3f216b356b121a83ef10cb0c8131a90b9ab803edebf23b882d9cf89" }, "generator": "operatorstack/intelligence-flow:boatstack-distribution", "schema_version": 1, "source": { - "commit": "c288814c89139fa36e7b914ce14d9917f12d32d0", + "commit": "c9e110ae06ef139d8ae336262558bc8bf21a1e2a", "path": "labs/12-product-engineering-loop", "repository": "operatorstack/intelligence-flow" } diff --git a/boatstack/AGENTS.md b/boatstack/AGENTS.md new file mode 100644 index 0000000..96c520d --- /dev/null +++ b/boatstack/AGENTS.md @@ -0,0 +1,62 @@ +# Agent guide — Boatstack product-engineering-loop + +Read this before opening a PR that touches anything under +`labs/12-product-engineering-loop/`. + +## Every PR that changes this lab REQUIRES a new release note + +CI runs `scripts/release_notes.py check-policy` (the **Generated distribution** +check). It fails the PR if the diff touches **any** file under +`labs/12-product-engineering-loop/` — source, tests, docs, scripts, anything — +without **adding** a new release-note fragment. This check is **not** part of +`go test ./...`, so a green local test run does **not** mean you are done. Skipping +the note costs a full CI round trip (fail → add note → push → re-run). + +### Add the note in the same commit as your change + +Create one new file per PR: + +``` +labs/12-product-engineering-loop/boatstack-distribution/release-notes/YYYY-MM-DD-.md +``` + +Contract (enforced by `validate_release_note`): + +- **Name:** `YYYY-MM-DD-.md`, slug lowercase `[a-z0-9]` words joined by `-`. +- **First line:** a level-three Markdown heading — `### ` (no leading blank line). +- **Body:** at least one non-empty line after the heading describing **user impact** + (what changed for someone using Boatstack, not the code mechanics). +- **Encoding/EOL:** UTF-8, and the file must end with a trailing newline. +- **Append-only:** never edit or delete an existing note. To correct a shipped + note, add a new correction fragment. Only added (`A`) files under + `release-notes/` are allowed in the diff. + +### Verify locally before you push — avoid the CI round trip + +Commit your change **and** the note, then run the same policy CI runs: + +``` +# format check on the notes directory +python3 labs/12-product-engineering-loop/scripts/release_notes.py \ + validate --root labs/12-product-engineering-loop/boatstack-distribution/release-notes + +# append-only + "note present for lab changes" against origin/main (needs a clean, +# committed tree — it inspects the committed PR diff, not the working tree) +python3 labs/12-product-engineering-loop/scripts/release_notes.py \ + preflight --repo . --base-branch main +``` + +`preflight` fetches `origin/main` and checks the committed diff. `PASS` means the +**Generated distribution** check will pass; `BLOCKED` prints exactly what to fix. + +## Other checks that are not in `go test` + +- **Repository conformance** and **Runtime** (windows/macos/ubuntu) run in CI. + Locally, always run `go build ./...`, `go vet ./...`, and `go test ./...` from + `product-engineering-loop`, plus `python3 -m unittest tests.test_product_loop` + from `labs/12-product-engineering-loop` for the Python surface. + +## PR body honesty + +Do not write "no release note required" for a change under this lab — a note is +always required. State which note you added. diff --git a/boatstack/pr.go b/boatstack/pr.go index 6119b95..bb96c42 100644 --- a/boatstack/pr.go +++ b/boatstack/pr.go @@ -391,6 +391,25 @@ func relativeSource(repo, path, kind string) (PRSource, error) { return PRSource{Kind: kind, Path: relative, SHA256: hash}, nil } +// featureArtifactPath resolves a feature artifact that may live in either the +// newer compiled/ subdirectory or the older feature-root layout. Candidates are +// tried in priority order (each artifact's canonical location first); the first +// that exists wins. When none exist the last candidate is returned so the +// downstream check reports a clear, canonical error path rather than a guessed +// one. This keeps the task graph and evidence resolution on one shared rule so +// the two layouts can never silently diverge. +func featureArtifactPath(directory string, candidates ...string) string { + var last string + for _, name := range candidates { + path := filepath.Join(directory, name) + last = path + if fileExists(path) { + return path + } + } + return last +} + func managedPRSources(repo, feature string) ([]PRSource, map[string]string, error) { directory := filepath.Join(repo, ".product-loop", "features", feature) planPath := filepath.Join(directory, "plan.md") @@ -411,7 +430,7 @@ func managedPRSources(repo, feature string) ([]PRSource, map[string]string, erro return nil, nil, fmt.Errorf("managed PR requires current approval: %w", err) } } - tasksPath := filepath.Join(directory, "compiled", "tasks.json") + tasksPath := featureArtifactPath(directory, filepath.Join("compiled", "tasks.json"), "tasks.json") if err := CheckApprovalLock(ApprovalOptions{ SourcePlanPath: check.SourcePlanPath, SpecPath: check.SpecPath, @@ -422,10 +441,7 @@ func managedPRSources(repo, feature string) ([]PRSource, map[string]string, erro }); err != nil { return nil, nil, fmt.Errorf("managed PR requires a current build lock: %w", err) } - evidencePath := filepath.Join(directory, "evidence.md") - if !fileExists(evidencePath) { - evidencePath = filepath.Join(directory, "compiled", "evidence.md") - } + evidencePath := featureArtifactPath(directory, "evidence.md", filepath.Join("compiled", "evidence.md")) if err := checkNonEmptyFile(evidencePath, "feature evidence"); err != nil { return nil, nil, err } diff --git a/boatstack/pr_test.go b/boatstack/pr_test.go index 1c75eb9..32c7a8b 100644 --- a/boatstack/pr_test.go +++ b/boatstack/pr_test.go @@ -156,6 +156,15 @@ func TestAdHocPRContextAndPreviewAreEvidenceLimited(t *testing.T) { } func activateManagedFeature(t *testing.T, repo, feature string) string { + t.Helper() + return activateManagedFeatureLayout(t, repo, feature, true) +} + +// activateManagedFeatureLayout activates a feature in either the newer compiled/ +// layout (compiled=true → OutDir=<feature>/compiled) or the older feature-root +// layout (compiled=false → OutDir=<feature>, tasks.json at the feature root, no +// compiled/ dir), so managed-PR resolution can be exercised against both. +func activateManagedFeatureLayout(t *testing.T, repo, feature string, compiled bool) string { t.Helper() directory := filepath.Join(repo, ".product-loop", "features", feature) if err := os.MkdirAll(directory, 0o755); err != nil { @@ -193,9 +202,13 @@ func activateManagedFeature(t *testing.T, repo, feature string) string { approvalPath = filepath.Join(directory, "approval.md") writeApprovalReceipt(t, approvalPath, check.Fingerprint) } + outDir := directory + if compiled { + outDir = filepath.Join(directory, "compiled") + } if err := ActivatePlan(ActivationOptions{ PlanPath: filepath.Join(directory, "plan.md"), ApprovalPath: approvalPath, - OutDir: filepath.Join(directory, "compiled"), OutputPath: filepath.Join(directory, "plan.lock.json"), + OutDir: outDir, OutputPath: filepath.Join(directory, "plan.lock.json"), SourceCommit: runGit(t, repo, "rev-parse", "HEAD"), }); err != nil { t.Fatal(err) @@ -257,6 +270,87 @@ No migration; revert the feature commit. return directory } +// TestFeatureArtifactPathResolvesBothLayouts pins the layout-resolution rule +// from the root up, independent of PR wiring: the canonical location is tried +// first, the alternate is the fallback, and when neither exists the last +// candidate is returned for a clear downstream error path. +func TestFeatureArtifactPathResolvesBothLayouts(t *testing.T) { + for _, test := range []struct { + name string + present []string + want string + }{ + {name: "only compiled", present: []string{filepath.Join("compiled", "tasks.json")}, want: filepath.Join("compiled", "tasks.json")}, + {name: "only root", present: []string{"tasks.json"}, want: "tasks.json"}, + {name: "both prefer canonical", present: []string{filepath.Join("compiled", "tasks.json"), "tasks.json"}, want: filepath.Join("compiled", "tasks.json")}, + {name: "neither returns last", present: nil, want: "tasks.json"}, + } { + t.Run(test.name, func(t *testing.T) { + directory := t.TempDir() + for _, rel := range test.present { + path := filepath.Join(directory, rel) + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte("x"), 0o644); err != nil { + t.Fatal(err) + } + } + got := featureArtifactPath(directory, filepath.Join("compiled", "tasks.json"), "tasks.json") + if got != filepath.Join(directory, test.want) { + t.Fatalf("resolved %q, want %q", got, filepath.Join(directory, test.want)) + } + }) + } +} + +// TestManagedPRSourcesAcceptsBothTaskGraphLayouts is the conformance guard for +// the build-lock layout bug: a feature activated in the older feature-root +// layout (tasks.json at the feature root, no compiled/ dir) must resolve its +// build lock exactly like the newer compiled layout, so the ship-gate is not +// blocked after build/test/review all passed. +func TestManagedPRSourcesAcceptsBothTaskGraphLayouts(t *testing.T) { + for _, test := range []struct { + name string + compiled bool + }{ + {name: "compiled layout", compiled: true}, + {name: "feature-root layout", compiled: false}, + } { + t.Run(test.name, func(t *testing.T) { + repo := prTestRepo(t) + feature := "cta-transport-feedback" + directory := activateManagedFeatureLayout(t, repo, feature, test.compiled) + + if !test.compiled { + if !fileExists(filepath.Join(directory, "tasks.json")) { + t.Fatal("feature-root fixture must place tasks.json at the feature root") + } + if fileExists(filepath.Join(directory, "compiled", "tasks.json")) { + t.Fatal("feature-root fixture must not have a compiled/tasks.json") + } + } + + sources, statuses, err := managedPRSources(repo, feature) + if err != nil { + t.Fatalf("managed PR sources must resolve for the %s: %v", test.name, err) + } + if statuses["test"] != "PASS" || statuses["review"] != "PASS_WITH_GAPS" { + t.Fatalf("unexpected gate statuses: %+v", statuses) + } + found := false + for _, source := range sources { + if source.Kind == "plan_lock" { + found = true + } + } + if !found { + t.Fatalf("managed PR sources missing plan_lock: %+v", sources) + } + }) + } +} + func TestManagedPRRechecksCurrentAuthorizationAndGapPolicy(t *testing.T) { t.Run("policy activation omits approval source", func(t *testing.T) { repo := prTestRepoConfigured(t, func(config *ProjectConfig) { diff --git a/docs/evidence-engineered-coding.md b/docs/evidence-engineered-coding.md index ed3a630..21bb899 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 [`c288814c89139fa36e7b914ce14d9917f12d32d0`](https://github.com/operatorstack/intelligence-flow/tree/c288814c89139fa36e7b914ce14d9917f12d32d0/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 [`c9e110ae06ef139d8ae336262558bc8bf21a1e2a`](https://github.com/operatorstack/intelligence-flow/tree/c9e110ae06ef139d8ae336262558bc8bf21a1e2a/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 f1a3538..3636c26 100644 --- a/docs/public-claims.json +++ b/docs/public-claims.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "source_commit": "c288814c89139fa36e7b914ce14d9917f12d32d0", + "source_commit": "c9e110ae06ef139d8ae336262558bc8bf21a1e2a", "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" }, { "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:c288814c89139fa36e7b914ce14d9917f12d32d0" + "last_verified_version": "source:c9e110ae06ef139d8ae336262558bc8bf21a1e2a" } ] } diff --git a/labs/diagram-json/plan.lock.json b/labs/diagram-json/plan.lock.json index 568866e..29346bb 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": "c288814c89139fa36e7b914ce14d9917f12d32d0", + "source_commit": "c9e110ae06ef139d8ae336262558bc8bf21a1e2a", "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-23-managed-pr-task-graph-layout.md b/release-notes/2026-07-23-managed-pr-task-graph-layout.md new file mode 100644 index 0000000..caf978d --- /dev/null +++ b/release-notes/2026-07-23-managed-pr-task-graph-layout.md @@ -0,0 +1,5 @@ +### Resolve managed-PR build lock across both feature layouts + +Boatstack managed PR preparation no longer blocks the ship gate for features whose plan lock was written in the older feature-root layout. Previously `managedPRSources` looked for the task graph only at `<feature>/compiled/tasks.json`; a feature activated with `tasks.json` at the feature root (no `compiled/` directory) failed the build-lock check with `task_graph` mismatch and reported "managed PR requires a current build lock" even after build, test, and review had passed. + +The task graph is now resolved across both layouts through a single shared resolver that also backs evidence resolution, preferring each artifact's canonical location and falling back to the alternate. Features activated in either layout prepare their managed PR identically; no migration is required.