Skip to content

Commit 304e4ee

Browse files
Sync Boatstack from Intelligence Flow Labs @ 4db21095ddba (#148)
Co-authored-by: operator-stack-publisher[bot] <operator-stack-publisher[bot]@users.noreply.github.com>
1 parent 256b161 commit 304e4ee

15 files changed

Lines changed: 397 additions & 30 deletions

CONTRIBUTING.md

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

33
# Contributing
44

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

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

UPSTREAM.json

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
},
1313
"files": {
1414
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
15-
"CONTRIBUTING.md": "16a84cf6a740fe70a920537a534dfb11f00273204d83a9f8f23661dca7d5331d",
15+
"CONTRIBUTING.md": "eac65d45c4f20dd219708eeee3f435d37663fbf23e6383cca97b1324e0d0d781",
1616
"README.md": "3ce3e95e511089b44e946a44b8d5f4f81d019ece5336db65b2cab1f9dc4d4dad",
1717
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
1818
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
@@ -49,16 +49,18 @@
4949
"boatstack/command.go": "4726ac515dedab4947be7eb48f88c6cb8b53d674124504b69f03e6396b080ee8",
5050
"boatstack/command_test.go": "9f707abba3640add81c3e97ba7e72fedbf98f3394b1c060a9ca4b4a28e919968",
5151
"boatstack/compiled_artifact_resolution_test.go": "0748d67643263e698211eb04d46464e1dd3db15d94537f5fd5092b5aa689745b",
52-
"boatstack/config_documentation_test.go": "aaecea04ee178ecf7872fff23a64014a3968dce1e7624e61a9453567e99969a9",
52+
"boatstack/config_documentation_test.go": "cb0ab6f13162909a0a0b60bddc0dfb10b3492639b336a4d2eb36e819c25cc3be",
5353
"boatstack/content_effect_conformance_test.go": "ebf4f6d50af0a76722177c717c79d33921948b9c06bec2e9d062769dce32b8aa",
5454
"boatstack/context.go": "02510af176d2d040c0080086f06d1235e76a1d47fef5176f96f740ad18d27660",
5555
"boatstack/decision.go": "257ca328da6ae19ab252f10ee5d06bd7daf49dd8141d083ab1b32f106ea7a94c",
5656
"boatstack/decision_test.go": "1a92ff832610f9559bd47ccac7fc1755a8b4f8261c35bc72a092830dff05f7c0",
57-
"boatstack/delivery.go": "1cbc917eaa7df569f09c71352db157dff743827d5310dccb63acb7be72ccf9d5",
57+
"boatstack/delivery.go": "a9a266d0413b25276d9bcfeb8328ac3ca4b3020ada1f97912251f68b4a9b5019",
5858
"boatstack/delivery_boundary_conformance_test.go": "53dde765046420b9119e82034d137742e600019938ed908c608f725d8a0c84c6",
5959
"boatstack/delivery_migrate.go": "7566e49f9c1838d4d563866e941c7aacd61ac918c9e886222282398d287ca780",
6060
"boatstack/delivery_migrate_conformance_test.go": "b8ba53681e1d0361ac62b06586c62b7763d55a65b5427976b5289e1fb1503bdc",
6161
"boatstack/delivery_reactivation_test.go": "573a2dba0034bc4290478414e3bdd8670b06a326128eb0295d77e748ecc8689e",
62+
"boatstack/delivery_terminal.go": "56fd8bec4d2c00ee3757bde5999417e5be763ab83cd7b68d4bccbbdea23af26a",
63+
"boatstack/delivery_terminal_conformance_test.go": "50b88bdfb9bdfc9dc50c11f46276e1eb13eed61618e75b4c951dfa2ac6075df0",
6264
"boatstack/delivery_test.go": "45c48ff7581c911bcaf821c3e4241d4ae2a9bb4aa682485cc58b6ad8fe1c85bf",
6365
"boatstack/deliverycontrol_parity_test.go": "f8662cfc35043395a0e1eef8a87051c2120752f38b09c56b78f82896008f1b65",
6466
"boatstack/denial.go": "ce77240edafb2589565ff3821b4e2cf8be3cf5884b1467d606265ca877188d3e",
@@ -71,11 +73,11 @@
7173
"boatstack/detached_test.go": "6cc70d15baa9a69afacf66ea29ce112efeb166836acb0a52bf9c4bb4c898cee5",
7274
"boatstack/docs/control-law-scoping.md": "0ae984821248eabda8c0eeaf201b367991e6742984e7c718df20ecc24caee475",
7375
"boatstack/evidence.go": "497a31e6ff632cb1d7c3adfc9f269af3f6aa84e948dd5d417c162767542a27df",
74-
"boatstack/export.go": "ca5c284fc658b112f58145e80b2bbfdd33a72b153a97922e2cf8c3f6e98fefb3",
76+
"boatstack/export.go": "12c4e8c3b0692736ead73c613e0410b0ed5f7cb4c6b6a9fcc96e59547f2fe566",
7577
"boatstack/export_test.go": "dce5aa3ab5499c82d05859cf86b46dfcee308482491366d83e10ca3fb8605bb6",
7678
"boatstack/flow_coding.go": "9fa53a0204f98a25f97775c3acf37392a591c14ce850b44aa587b5806e770bb9",
7779
"boatstack/flow_coding_test.go": "dddcd7a85892d4fa10af42739d4c1ff265721b0313e27b6e7a1bbb019d5c3b51",
78-
"boatstack/flow_control.go": "43204356017b837148bd1505779611fbe781097839c2944f41a437a4ec755a82",
80+
"boatstack/flow_control.go": "193dcae29e0611001b33ea23011beeb921d626562a5c733658c585ebca62b7fe",
7981
"boatstack/flow_control_test.go": "02d788c83be55ebd79ffc73875bfd019de45325151eb1f70f506980eb8e77f29",
8082
"boatstack/flow_drive.go": "a501ceda390dfd3605e22cf7ecfa15f9d50240b3fac6ebb2bb2d80c615d0a9fc",
8183
"boatstack/flow_drive_conformance_test.go": "23edea926c271a1f5718fb9dae1da11e4bf03cceb1357290cd61cd8ffb73beda",
@@ -164,7 +166,7 @@
164166
"boatstack/reexec_unix.go": "ff86157a9aa20c82a56fcd859b70669b7eacf4e0a9f61a4546ef33808437939e",
165167
"boatstack/reexec_windows.go": "f5335c8c28cb4e89048b058b1c4d12f78644f99acb4f6167ff60e622dfb9e742",
166168
"boatstack/references/artifacts.md": "4f27170227ffa2715d632eab4cbdca229726c5fc03c4b0f2af980fa50bb24725",
167-
"boatstack/references/config-schema.md": "eff8586850eca9941df1cea29ac7edb779277ed9bd6d938a1980db5028d28cf4",
169+
"boatstack/references/config-schema.md": "a6860ec7e1cd155e7e36dc465b8cae79de896714751e1c04dfa68d3f5c4a45e0",
168170
"boatstack/references/failure-moves.md": "b65ef72035afa6ad0dce589a0b38f84bc40cde3864c9ecf973f08fc687f001c3",
169171
"boatstack/references/host-hook-contracts.md": "2a89d44d0e418a53f2e3b6300fed957cdf878f45ea97ce24b55b66065f0eaa1d",
170172
"boatstack/references/irreversible-operation-boundary.md": "e0076f0fea3bf729b2e9bdf353eaeaaf7cdafabfaf26b8d9b27287e5414c2441",
@@ -175,7 +177,7 @@
175177
"boatstack/repair_state_test.go": "f3779ac47c3db3927175a545728d3b2e020dbc85f41394d8235753b52afc3739",
176178
"boatstack/run.go": "3127e8c054b80e41413011e423ba9463fe06a7e6c9e1e71750ab98587871d89d",
177179
"boatstack/run_test.go": "5b291510fa90cefdc26eb89e18a3443385456a6ebc73408325ac1945b7c084d6",
178-
"boatstack/runtime.go": "7dc5d033ec11bbcf9a4561da66d4d6692a071bc79ac2fe4eb66feaced358d3c3",
180+
"boatstack/runtime.go": "368bb43a0e3042bde2d4bab1b62df560a93f5928384c7c8f5e27e8a836628af4",
179181
"boatstack/runtime_cache.go": "e026ffc1906f7e1e98b768bae63e6658164d2826c07169c9121ce0f23c73faf8",
180182
"boatstack/runtime_cache_test.go": "b981467ddc9f0f562da6bff5de7a80a9fe5a433a0317541d1e48df268546ac85",
181183
"boatstack/runtime_provenance_test.go": "1d52f1e6b0691cf4667729cc9b9f3c55c128f0aa3321f3a2843a9aa6fd0e73dc",
@@ -209,11 +211,11 @@
209211
"docs/account-recovery-walkthrough.md": "676034974594a7d1a559b24dbed31d7ccc429eb81404b203ca07bbdaa19ec3d3",
210212
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
211213
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
212-
"docs/configuration.md": "060775c73431f28bd16066bdf9e0f89034d2855c7ca0f5544f660d24b91211d0",
213-
"docs/evidence-engineered-coding.md": "f0567d8bb1fdf42d78ca7dac28603042a78e2290487a6fce8518ff16b8307fd2",
214+
"docs/configuration.md": "221f979506a3a9de357e5277f1329c345bf175346ec8dfc8fdd1212fb100dea1",
215+
"docs/evidence-engineered-coding.md": "223d5b3a75c66eccbaa8d4a0b755bfb873fe0684106004b841e8319653e702ef",
214216
"docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3",
215217
"docs/getting-started.md": "51c2823f21e35140d31e6d5083dc4b89fddd24721ac6acc474154a4da53ee9f8",
216-
"docs/public-claims.json": "ff6bba756adaa499998016d2e4986c7fdfe7bc6f5d3ae7531bbc4471a6371a8b",
218+
"docs/public-claims.json": "9f640af54667625048eddfbb78dd63a0c055c556affc4c105d186ca164467e2f",
217219
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
218220
"docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6",
219221
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
@@ -227,7 +229,7 @@
227229
"labs/diagram-json/compiled/evidence.md": "1ba1c989ade070a8ef9a508fbd788d100d7292f2dbacbb2bce895468019f619d",
228230
"labs/diagram-json/compiled/tasks.json": "88f60851abf79d851e9fccc754ff3040034ae595306bc87d64784c19eb403e71",
229231
"labs/diagram-json/compiled/test-matrix.json": "424657ff505768e50fa113801fd8363364a18269d5297480907a993d44063a39",
230-
"labs/diagram-json/plan.lock.json": "73fe60031dd4c5b25b28fbbb29654416359a4040b1d7bf124618aede0e482633",
232+
"labs/diagram-json/plan.lock.json": "030278e2649c63a717a744ef91926fef25fc1648cedef91b4d2edafaf9e8d4ce",
231233
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
232234
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
233235
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
@@ -356,6 +358,7 @@
356358
"release-notes/2026-07-27-repeated-denials-escalate.md": "ee54b597e593ce74d8d9acbc67c74d2d8cb972ff206f618e08a047d4d962d7af",
357359
"release-notes/2026-07-27-sandboxed-migration-grading.md": "03cebc372bbdfed37cc70d18f3b6374d1aa5e585bafefa073dbcced58bd0336a",
358360
"release-notes/2026-07-27-state-ownership-map.md": "d032547aafc1a4acbeb520f6cbb59d7757de4f33fe824701d7b5ea8cd8c8b9e7",
361+
"release-notes/2026-07-28-configurable-delivery-terminal.md": "54f42d8ee04f16429f7f6db484c12247a75dd365d9028ec6c24b2efb92f9e700",
359362
"release-notes/2026-07-28-flow-frontier-dashboard.md": "9a768e0fd67f122bc0aef99899314f0a8530189164fb560b536ee03f20e29081",
360363
"release-notes/2026-07-28-flow-watch-loop.md": "54833887e733c65626c3bb7f0e6430eca8028f0fe19aa2cd31cdbdcc6ff4d8ba",
361364
"release-notes/2026-07-28-minimum-app-permissions.md": "9ef97e32e5591966ef34ba23f4e0a7aa14d061a4ac5f72f5f4dcecc9bfb62a89",
@@ -367,7 +370,7 @@
367370
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
368371
"schema_version": 1,
369372
"source": {
370-
"commit": "5850912e0d947f9fbee5048d9ed6a79a5d614ff1",
373+
"commit": "4db21095ddbad477daa4a04cd4d0827d9ba2fb8b",
371374
"path": "labs/12-product-engineering-loop",
372375
"repository": "operatorstack/intelligence-flow"
373376
}

boatstack/config_documentation_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func TestSerializedConfigurationSurfaceIsDocumentedInternally(t *testing.T) {
113113
func TestPublicConfigurationGuideContainsOnlySupportedUserControls(t *testing.T) {
114114
want := []string{
115115
"adapters",
116+
"delivery.terminal",
116117
"project.commands",
117118
"project.context",
118119
"project.default_branch",

boatstack/delivery.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ type DeliveryState struct {
6666
RepairAttempt int `json:"repair_attempt,omitempty"`
6767
SupersededReceipts []string `json:"superseded_receipts,omitempty"`
6868
ParentDelivery string `json:"parent_delivery,omitempty"`
69+
// Goal snapshots the non-default delivery terminal ("merged") this
70+
// delivery was activated under, so a mid-flight config change never
71+
// silently changes an in-progress delivery's goal. Empty means: resolve
72+
// from config at read time (and keeps a default-config state file
73+
// byte-identical to the pre-field format).
74+
// control-law: terminal-goal-defaults-to-published-and-hydrates-from-state-then-config
75+
Goal string `json:"goal,omitempty"`
6976
}
7077

7178
type DeliveryGateReceipt struct {
@@ -377,6 +384,7 @@ func initializeDeliveryState(repo, feature, planPath, lockPath string) error {
377384
SchemaVersion: deliveryStateSchemaVersion, Feature: feature, PlanLockHash: lockHash,
378385
ActiveIndex: 0, Slices: slices, Mode: "NORMAL",
379386
ParentDelivery: strings.TrimSpace(stringValue(plan["parent_delivery"])),
387+
Goal: deliveryGoalSnapshot(repo),
380388
})
381389
}
382390

@@ -485,6 +493,7 @@ func reconcileAmendedDeliveryState(existing DeliveryState, newSlices []DeliveryS
485493
Slices: merged,
486494
Mode: "NORMAL",
487495
ParentDelivery: existing.ParentDelivery,
496+
Goal: existing.Goal,
488497
}
489498
}
490499

boatstack/delivery_terminal.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package boatstack
2+
3+
import "strings"
4+
5+
// The delivery terminal is the standing goal of the flow — the state past
6+
// which nothing more is owed. It resolves in a fixed order: the goal the
7+
// delivery was ACTIVATED under (state.Goal — hysteresis, so a mid-flight
8+
// config change never silently changes an in-progress delivery's goal), then
9+
// the repository config (delivery.terminal), then the published default.
10+
// Every unreadable or invalid input resolves to the narrower published goal:
11+
// a goal is widened only by an explicit, verifiable operator choice.
12+
// control-law: terminal-goal-defaults-to-published-and-hydrates-from-state-then-config
13+
type DeliveryTerminal string
14+
15+
const (
16+
// TerminalPublished — the flow is done when the slice's PR is open.
17+
TerminalPublished DeliveryTerminal = "published"
18+
// TerminalMerged — the flow keeps naming read-only post-publish steps
19+
// until the PR is observed merged.
20+
TerminalMerged DeliveryTerminal = "merged"
21+
)
22+
23+
func normalizeDeliveryTerminal(value string) (DeliveryTerminal, bool) {
24+
switch strings.ToLower(strings.TrimSpace(value)) {
25+
case string(TerminalPublished):
26+
return TerminalPublished, true
27+
case string(TerminalMerged):
28+
return TerminalMerged, true
29+
default:
30+
return "", false
31+
}
32+
}
33+
34+
// configuredDeliveryTerminal reads the repository's standing terminal from
35+
// the project config. Absent, invalid, or unreadable configuration resolves
36+
// to published — never an error, because the terminal is consulted from
37+
// read-only paths that must not gain a new failure mode.
38+
func configuredDeliveryTerminal(repo string) DeliveryTerminal {
39+
config, _, err := LoadConfig(WorkspaceFor(repo).ProjectConfigPath())
40+
if err != nil || config.Delivery == nil {
41+
return TerminalPublished
42+
}
43+
if terminal, ok := normalizeDeliveryTerminal(config.Delivery.Terminal); ok {
44+
return terminal
45+
}
46+
return TerminalPublished
47+
}
48+
49+
// resolveDeliveryTerminal resolves the terminal for one feature: the
50+
// activation snapshot first, then config, then the default.
51+
func resolveDeliveryTerminal(repo, feature string) DeliveryTerminal {
52+
if strings.TrimSpace(feature) != "" {
53+
if state, err := LoadDeliveryState(repo, feature); err == nil {
54+
if terminal, ok := normalizeDeliveryTerminal(state.Goal); ok {
55+
return terminal
56+
}
57+
}
58+
}
59+
return configuredDeliveryTerminal(repo)
60+
}
61+
62+
// deliveryGoalSnapshot is what activation records on the new delivery state.
63+
// Only the non-default goal is snapshotted: a default-config delivery keeps
64+
// an empty Goal, so its persisted state is byte-identical to before this
65+
// field existed.
66+
func deliveryGoalSnapshot(repo string) string {
67+
if configuredDeliveryTerminal(repo) == TerminalMerged {
68+
return string(TerminalMerged)
69+
}
70+
return ""
71+
}

0 commit comments

Comments
 (0)