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/f42f1a845ecc6e5905d6e38dca863749cc19f0c0/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/146f50c0f3309e592ed45374b8cddb3d8ed64d85/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
29 changes: 15 additions & 14 deletions UPSTREAM.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"files": {
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
"CONTRIBUTING.md": "970762fd2bd13341d06dcef8929099dc3b71b246f3bc52e1e53e9df6957c5c68",
"CONTRIBUTING.md": "c3334d810923b2cf4a745dae0aecc859d5de7cdafc94c0d193fb7d7b08892c53",
"README.md": "3ce3e95e511089b44e946a44b8d5f4f81d019ece5336db65b2cab1f9dc4d4dad",
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
Expand All @@ -38,8 +38,8 @@
"boatstack/attach.go": "6a855440fac9acc63be857efef9d76210a4619774728684832dfbb08caf42a30",
"boatstack/capability.go": "fc6bccb0ce4df579b81252ecffeb23c68d62f02ff041bfec980d844baf0885a3",
"boatstack/capability_test.go": "e8322903a843970d7f0317d2629466532cb05c3ffcb44b9423adf4219faa8021",
"boatstack/capture.go": "0e137d8251a658118bd56812040575d01f02fd2f862c80ef761b253db6b35bbe",
"boatstack/capture_test.go": "31a8afa40a54ae716fea1ea44be3b41705ed171789a181d1ef26432855c05c9e",
"boatstack/capture.go": "98a29fedcd7f6a95fadc9bac8c1bd601fee24c17cd64a6a76892e068f040ef66",
"boatstack/capture_test.go": "7072d0c5f9ab0ea9ef493f9e6dcb01cf0de544514c8201e30b8e4e6a4065505a",
"boatstack/changelog.go": "6b06be7cd9738de29ba6e87aa2569f3b027a2e618b04524f5abd7abaa17945bf",
"boatstack/changelog_test.go": "ce792f23a7fe1e09fb3096cd1314130a6ab69321d4877b12a8e994027541baf7",
"boatstack/cmd/boatstack-helper/coverage_conformance_test.go": "f5a931d2b5cdb0d32af85acbbd499fa0f509ed36d62e772e6b6072e348200aca",
Expand All @@ -64,7 +64,7 @@
"boatstack/delivery_terminal_conformance_test.go": "50b88bdfb9bdfc9dc50c11f46276e1eb13eed61618e75b4c951dfa2ac6075df0",
"boatstack/delivery_test.go": "45c48ff7581c911bcaf821c3e4241d4ae2a9bb4aa682485cc58b6ad8fe1c85bf",
"boatstack/deliverycontrol_parity_test.go": "706be08bdc89192cf200f0b2cf889c8f4bb0e666a5d8a557996d7215101ce2ca",
"boatstack/denial.go": "507593c091c7ee80a3a4f0299d247d616a85331bc1c0aaf2d69f8a2e7aaf6f1c",
"boatstack/denial.go": "3b6419412c7672ca2dd9cf80140675b8326d6b54460bbcb650cf3dde48dddd56",
"boatstack/denial_escalation_conformance_test.go": "d50f0e1c803c8f5731a46dbe6f82c7935c0ccbd582f513cbe07211f5e902157e",
"boatstack/denial_ledger.go": "a35bf8fd8c1f6b9302109cf0087e1b9158e43e07b92b18df5e589a637d58491d",
"boatstack/denial_solutions.go": "ae6cb218c01a89c14367242b21e2b96d85e1fda357076b7bffedb56066ef961b",
Expand Down Expand Up @@ -165,10 +165,10 @@
"boatstack/planning_first_write_conformance_test.go": "873097aa9384b75bf01e74a475f3ec2ac7cca4a28f733e82f2c82959032c6a30",
"boatstack/planning_test.go": "06ec7022222d926040c3ae28b84ab50c3d2f804ae6473e61b303804dd992d884",
"boatstack/post_publish_prescribe_conformance_test.go": "3c20d359ff84648db7dedb227b4d64e6574d9f41d3cdca0adefec1c60bfbf4ae",
"boatstack/pr.go": "3c7088e47c997a0b6c25e40dad56a1662be0451c025f39460b4b62961cb2a634",
"boatstack/pr.go": "c389bd5fddf788290069eb858e1062433d1ff4dff928855a5211ac470c67ccd7",
"boatstack/pr_phase.go": "59f8cbb75b6b538a5345474acd6a725450979579bf8ecf9591956cbbe1cc4737",
"boatstack/pr_phase_conformance_test.go": "bc9c834e9c4ed43b35d81abafd7b1bf2a264ea2a8c4a4ec9758ee18d1d438968",
"boatstack/pr_test.go": "89f6f88b1e3eb51efbe6faaff8586bd930d4c868fae5eafd48e1746b919c27a7",
"boatstack/pr_test.go": "5c0ff03eb21e383026a4e9fbc5671b2e316040e4e4c55ab6583b930e7e117dda",
"boatstack/provenance.go": "d44dcd5421306269326f1202ba1d52df8c252490550270ef9d022e8ec2b65210",
"boatstack/provision.go": "eb7333a73331b011adc93f59a2d97415d850c2e588f0e2bbb5116984e2ef927d",
"boatstack/provision_test.go": "214e9edb991a66d5bbb696a7c1b63876d2f799f2cab4e3f40785f4e8f1eac57b",
Expand All @@ -182,7 +182,7 @@
"boatstack/reexec_unix.go": "ff86157a9aa20c82a56fcd859b70669b7eacf4e0a9f61a4546ef33808437939e",
"boatstack/reexec_windows.go": "f5335c8c28cb4e89048b058b1c4d12f78644f99acb4f6167ff60e622dfb9e742",
"boatstack/references/artifacts.md": "e362b2663c904beb8daa777c997f9fcb2ed0e70442ed2e7bef3b169895d170f1",
"boatstack/references/config-schema.md": "a6860ec7e1cd155e7e36dc465b8cae79de896714751e1c04dfa68d3f5c4a45e0",
"boatstack/references/config-schema.md": "01a3b7a9269a08a5cd2a86e967940c1e57f78e166db0b7289bff7a98732c8691",
"boatstack/references/failure-moves.md": "b65ef72035afa6ad0dce589a0b38f84bc40cde3864c9ecf973f08fc687f001c3",
"boatstack/references/host-hook-contracts.md": "2a89d44d0e418a53f2e3b6300fed957cdf878f45ea97ce24b55b66065f0eaa1d",
"boatstack/references/irreversible-operation-boundary.md": "e0076f0fea3bf729b2e9bdf353eaeaaf7cdafabfaf26b8d9b27287e5414c2441",
Expand All @@ -200,7 +200,7 @@
"boatstack/runtime_cache.go": "e026ffc1906f7e1e98b768bae63e6658164d2826c07169c9121ce0f23c73faf8",
"boatstack/runtime_cache_test.go": "b981467ddc9f0f562da6bff5de7a80a9fe5a433a0317541d1e48df268546ac85",
"boatstack/runtime_provenance_test.go": "1d52f1e6b0691cf4667729cc9b9f3c55c128f0aa3321f3a2843a9aa6fd0e73dc",
"boatstack/safety.go": "2f274b90a2b50798bc5a19a74ddaf4f2eecd66876234d21b3753406f69522170",
"boatstack/safety.go": "643837af3d76d819dc4e639a4ccd7c20934dcb2396636c28bdafa529f7a37b18",
"boatstack/safety_corpus_test.go": "824051705dd893338ac2246e2d75231703e36574cc9c23902237f72ab2d35960",
"boatstack/safety_test.go": "ddd7a72d4ff50c046aa46fd97b108d629cef27cf15816150b6d54baf5f1c4c36",
"boatstack/safety_update_publisher_test.go": "ed3f8187036623694dfe7c395cdae00fdae14609bab6124d1fdfc6fe73fa2196",
Expand All @@ -217,7 +217,7 @@
"boatstack/update_publication.go": "5c1ac8445345c6546d165b9321a736453b313ced96a0059465b8ad637498bac6",
"boatstack/update_publication_test.go": "c5f32578db53be65e35452d5e8b4520884354e4e80a370dcec19860ea644d091",
"boatstack/update_test.go": "bf5f19f8499db6dd7356917d867b113b790548ab89bfdea59e2adf4999a82a6a",
"boatstack/visual_evidence.go": "4d69f98adb6087d4830e6703273ae6e03b28ec8b3c496a6e432fd5e0e54d8a2f",
"boatstack/visual_evidence.go": "f9fbde0e89f0ce8d9503939197d9b92cc8da377053007371d28360e29715a84a",
"boatstack/visual_evidence_test.go": "0fe8f5154ef4398dfeba5e7f7b387b2d279ed75635ea35d93ff392269f2cc6d0",
"boatstack/visual_publisher.go": "ec5e95228b48e4ec20731975606048f5e732c4e09a7fd175770d4b15e447cc88",
"boatstack/visual_publisher_test.go": "979f600edae00c77569ae753b80530e8cbf2e3b342995efcd992d351ff382eaf",
Expand All @@ -230,11 +230,11 @@
"docs/account-recovery-walkthrough.md": "676034974594a7d1a559b24dbed31d7ccc429eb81404b203ca07bbdaa19ec3d3",
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
"docs/configuration.md": "caa95f1dd484a71a9051951652d6457294c213999fe00fb764d05e8a509cc786",
"docs/evidence-engineered-coding.md": "d6d7babc0c4e61030a1e76754dc45f2bc40cdb7df88a9cf312e24aa9c06ce7c7",
"docs/configuration.md": "8c5b0a6a8394333165dd0b2b1a70ca74e9d53f784b478e2ef7f1b12d93bc03b0",
"docs/evidence-engineered-coding.md": "27da8a87d58783dc2ac2ad72cb2265cbdbab456f41fb4e09f261dbc44d90cd12",
"docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3",
"docs/getting-started.md": "51c2823f21e35140d31e6d5083dc4b89fddd24721ac6acc474154a4da53ee9f8",
"docs/public-claims.json": "962bde13802724ae3ad87955bec0e48e0d4274385703be509308c43a7e91674f",
"docs/public-claims.json": "3bf81d5a1ca4371fc34a6b25eddd156da6c3e1cda728785cf3a0559a0d367596",
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
"docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6",
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
Expand All @@ -248,7 +248,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": "963e46963033dc5911e2cdd4a034f0aff909fb6c7e966a224d854b6fa9d7c447",
"labs/diagram-json/plan.lock.json": "2c861b4174ba2e09d859ff9463f62e0e5ffb4198db121cb426246b206cc697a4",
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
Expand Down Expand Up @@ -391,12 +391,13 @@
"release-notes/2026-07-28-retromine-recurrence-detector.md": "27790993a02e73f3a2700dce7340d044aeb0e52f785ded68271ff6673add9e25",
"release-notes/2026-07-29-readiness-and-journey-control.md": "2411db76974990ad0128fcd90e795c4c1c5c70d6d6f15fccd452f7e1a242310b",
"release-notes/2026-07-30-auto-capture-on-ship.md": "49aa077ac52005d380ba2cae9e406c7d0a9941157c40aa4ed44b9e59195b3837",
"release-notes/2026-07-30-plan-approved-scenarios-escalate-to-require.md": "21c3f2be51b834fc2eb7662236db2549e80b1a1a0665a0721e773b7736e2c079",
"release-notes/2026-07-30-visual-evidence-survives-preview-commit.md": "71d19e9fabb40e8cb1e939f26bf288911d227979926f43f337046c6cf6b66551"
},
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
"schema_version": 1,
"source": {
"commit": "f42f1a845ecc6e5905d6e38dca863749cc19f0c0",
"commit": "146f50c0f3309e592ed45374b8cddb3d8ed64d85",
"path": "labs/12-product-engineering-loop",
"repository": "operatorstack/intelligence-flow"
}
Expand Down
5 changes: 4 additions & 1 deletion boatstack/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ func CaptureEvidence(options CaptureEvidenceOptions) (PRVisualEvidenceManifest,

manifest := PRVisualEvidenceManifest{
Key: key,
Policy: config.Workflow.PRVisualEvidence,
// The manifest records the configured policy verbatim (informational);
// the effective policy — including plan-escalated require semantics —
// is re-derived by resolvePRVisualEvidence at every decode.
Policy: config.Workflow.PRVisualEvidence,
Relevance: relevance,
RelevanceSource: source,
Status: "PASS",
Expand Down
2 changes: 1 addition & 1 deletion boatstack/capture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestCaptureEvidenceProducesManifestTrustedByPRContext(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, status, count, _, _, _, resolved, err := resolvePRVisualEvidence(repo, config, "managed", "reviewer-ready", head, diffHash)
_, status, count, _, _, _, _, resolved, err := resolvePRVisualEvidence(repo, config, "managed", "reviewer-ready", head, diffHash)
if err != nil {
t.Fatal(err)
}
Expand Down
3 changes: 3 additions & 0 deletions boatstack/denial.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@ func denialFor(host string, finding SafetyFinding) Denial {
}
d.Qualifier = "visual evidence is owed"
d.Detail = "PR publication is blocked until required visual evidence is current for " + target + "."
if finding.PolicySource == "plan-escalated" {
d.Detail += " The approved plan declares visual scenarios, so the configured suggest policy ships with require semantics for this feature."
}
if reason := strings.TrimSpace(finding.Reason); reason != "" {
d.Detail += " Automatic capture reported: " + reason + "."
}
Expand Down
25 changes: 19 additions & 6 deletions boatstack/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type PRContext struct {
PRVisualEvidenceFingerprint string `json:"pr_visual_evidence_fingerprint"`
PRVisualEvidenceRelevance string `json:"pr_visual_evidence_relevance"`
PRVisualEvidenceSource string `json:"pr_visual_evidence_source"`
// PRVisualEvidencePolicySource is "configured", or "plan-escalated" when
// a plan-approved visual decision lifts suggest to require semantics.
PRVisualEvidencePolicySource string `json:"pr_visual_evidence_policy_source,omitempty"`
// PRVisualEvidenceCaptureDetail explains why automatic capture could not
// produce current evidence. Deliberately outside the context fingerprint:
// a flaky harness message must not destabilize preview equality.
Expand Down Expand Up @@ -183,20 +186,28 @@ func boundedCaptureDetail(detail string) string {
return detail
}

func resolvePRVisualEvidence(repo string, config ProjectConfig, mode, feature, head, diffHash string) (string, string, int, string, string, string, *PRVisualEvidenceManifest, error) {
func resolvePRVisualEvidence(repo string, config ProjectConfig, mode, feature, head, diffHash string) (string, string, int, string, string, string, string, *PRVisualEvidenceManifest, error) {
policy := normalizedPRVisualEvidencePolicy(config.Workflow.PRVisualEvidence)
relevance, source := "unresolved", "agent-proposed"
var scenarios []PRVisualScenario
if mode == "managed" {
var err error
relevance, source, scenarios, err = planVisualDecision(repo, feature)
if err != nil {
return "", "", 0, "", "", "", nil, err
return "", "", 0, "", "", "", "", nil, err
}
}
// The effective policy is what everything downstream (coercion, preview
// frontmatter, the publication block) reads. Escalation keys on the
// plan's own decision, before any manifest overrides it.
policySource := "configured"
if visualEscalationApplies(policy, relevance, len(scenarios)) {
policy = "require"
policySource = "plan-escalated"
}
key, err := visualEvidenceKey(mode, feature, head)
if err != nil {
return "", "", 0, "", "", "", nil, err
return "", "", 0, "", "", "", "", nil, err
}
status := "NOT_APPLICABLE"
var manifest *PRVisualEvidenceManifest
Expand Down Expand Up @@ -235,9 +246,9 @@ func resolvePRVisualEvidence(repo string, config ProjectConfig, mode, feature, h
}
raw, err := MarshalJSON(payload)
if err != nil {
return "", "", 0, "", "", "", nil, err
return "", "", 0, "", "", "", "", nil, err
}
return policy, status, count, SHA256Bytes(raw), relevance, source, manifest, nil
return policy, status, count, SHA256Bytes(raw), relevance, source, policySource, manifest, nil
}

type PRPublishOptions struct {
Expand Down Expand Up @@ -735,7 +746,7 @@ func PreparePRContext(options PRContextOptions) (PRContext, error) {
if err != nil {
return PRContext{}, err
}
visualPolicy, visualStatus, visualCount, visualFingerprint, visualRelevance, visualSource, visualManifest, err := resolvePRVisualEvidence(
visualPolicy, visualStatus, visualCount, visualFingerprint, visualRelevance, visualSource, visualPolicySource, visualManifest, err := resolvePRVisualEvidence(
repo, config, mode, options.Feature, head, SHA256Bytes(diff),
)
if err != nil {
Expand All @@ -762,6 +773,7 @@ func PreparePRContext(options PRContextOptions) (PRContext, error) {
PRVisualEvidencePolicy: visualPolicy, PRVisualEvidenceStatus: visualStatus,
PRVisualEvidenceCount: visualCount, PRVisualEvidenceFingerprint: visualFingerprint,
PRVisualEvidenceRelevance: visualRelevance, PRVisualEvidenceSource: visualSource,
PRVisualEvidencePolicySource: visualPolicySource,
PRVisualEvidenceCaptureDetail: captureDetail,
PRVisualEvidence: visualManifest,
PreviewPath: previewPath,
Expand Down Expand Up @@ -1127,6 +1139,7 @@ func PublishPR(options PRPublishOptions) (string, error) {
Source: "publication",
BlockingFeature: context.Feature,
Reason: context.PRVisualEvidenceCaptureDetail,
PolicySource: context.PRVisualEvidencePolicySource,
}
return "", fmt.Errorf("%s", denialWithOptions(repo, "", finding).Render(RenderPlain))
}
Expand Down
Loading
Loading