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/fac1f242bb58f88e94da3f7cbb50ba6159d02790/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/eec4b62c152cc2da37579f891706640bff9cb1a6/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
36 changes: 28 additions & 8 deletions UPSTREAM.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"files": {
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
"CONTRIBUTING.md": "762db520d51872c6b6b6ec7c312f54c7e1ef5c14fdf61ed17673d65a525a7e01",
"CONTRIBUTING.md": "ff655c8e8bb64b7c06dfd123aba96cabe03f30541e5d33c338933bf3c6baf45e",
"README.md": "6b7402c5cef5b3b9b739281d3d4d576cdc995796ff127fc6aefb97c5743e0bac",
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
Expand Down Expand Up @@ -40,8 +40,9 @@
"boatstack/capture_test.go": "63fa1177738081f1e862364d7a4257f5e259f8e9c36276ba1775b8085b277105",
"boatstack/changelog.go": "6b06be7cd9738de29ba6e87aa2569f3b027a2e618b04524f5abd7abaa17945bf",
"boatstack/changelog_test.go": "ce792f23a7fe1e09fb3096cd1314130a6ab69321d4877b12a8e994027541baf7",
"boatstack/cmd/boatstack-helper/main.go": "ac174deb556f9a0b5e033154f2fc966715b3bff81d26ef97a23df2f901c56652",
"boatstack/cmd/boatstack-helper/main_test.go": "ff73003b6a5157202fa09ddf1129fb13c3d79702b2e05a8721ce5a11bf5ab779",
"boatstack/cmd/boatstack-helper/flow.go": "795e6129351600cd81ffa86db5e1016dfae894c2d0e9b75615f37eb5fdf5f939",
"boatstack/cmd/boatstack-helper/main.go": "a4a29e53d803cd1d8ec35e105bab17000e2855f978393031f1516aab26c732b6",
"boatstack/cmd/boatstack-helper/main_test.go": "b36c52d6d5c9dd2428730de10ff18194b7e32a98722e41341c301c6f7a04cad5",
"boatstack/command.go": "4726ac515dedab4947be7eb48f88c6cb8b53d674124504b69f03e6396b080ee8",
"boatstack/command_test.go": "9f707abba3640add81c3e97ba7e72fedbf98f3394b1c060a9ca4b4a28e919968",
"boatstack/compiled_artifact_resolution_test.go": "0748d67643263e698211eb04d46464e1dd3db15d94537f5fd5092b5aa689745b",
Expand All @@ -56,6 +57,14 @@
"boatstack/evidence.go": "497a31e6ff632cb1d7c3adfc9f269af3f6aa84e948dd5d417c162767542a27df",
"boatstack/export.go": "9cb23234e6cd79441ff6f39f88ed66d6d47ef7c27901404439a3572b03fdf881",
"boatstack/export_test.go": "dce5aa3ab5499c82d05859cf86b46dfcee308482491366d83e10ca3fb8605bb6",
"boatstack/flow_coding.go": "9fa53a0204f98a25f97775c3acf37392a591c14ce850b44aa587b5806e770bb9",
"boatstack/flow_coding_test.go": "dddcd7a85892d4fa10af42739d4c1ff265721b0313e27b6e7a1bbb019d5c3b51",
"boatstack/flow_control.go": "9eaa1188f86c307bf0f31a5ca465637e5fd6792f42206dce10d0272a1d1ea36b",
"boatstack/flow_control_test.go": "d52e095f2e0f18067abe03e3b5f7c98bc30f8b1c8f5230103797c599aec95013",
"boatstack/flow_guard.go": "dd18524d95f4a220cfd3d11b11003dacc52120785ee0ccdbeceb2307fab55872",
"boatstack/flow_guard_test.go": "8ba75f11ddd080427c15bd7e25f7d03c1b746a2f587c212cea0e710337d1c0e1",
"boatstack/flow_report.go": "9e58cec51c6c903847f3ebc79cd6bf25e2f91d14b81811e82e5f4e026a7b71a3",
"boatstack/flow_report_test.go": "eae00f2b8ead4f1ec20e1f1bc47db4c53a36048bb84eca9bea4f1a2105bdcdde",
"boatstack/flow_trace.go": "95b5a99f5f557a27a3eca7152de9ec18459f2a88d9749924432463031536a96c",
"boatstack/flow_trace_test.go": "99f89a831e904f6a8ef710b6977ed3a808ce1c7ddfaba457b292d84f2ddca51b",
"boatstack/go.mod": "6086ef1b2a83f5696190dca692c653925f27b61f652f659fd3fca43ed54a1641",
Expand All @@ -70,14 +79,21 @@
"boatstack/installation_repair.go": "6574f7133a9644843c9260b9b9daede641a14438f7357bae42fb8ec188890446",
"boatstack/installation_repair_test.go": "ae5a5ea1110836bd78cf20ade863a4d32cfd63d282559f92786f57b31869bd14",
"boatstack/integrations.go": "75b39ce2e662fccd66bf4b9bff0e097a4db558f23b3aa1d9bc83a5fc6373444c",
"boatstack/internal/deliverycontrol/advise.go": "4f3a53a785a34f6c34858236a57d4114091141a463b51e5aaefae3336557ae5a",
"boatstack/internal/deliverycontrol/advise_test.go": "6e0d3bda302cb5d26dd42a0253281ac6d1bb6749496b1a7df9c2aa9f53ea13a1",
"boatstack/internal/deliverycontrol/coding.go": "fe312c1aee11edcdbf24d7d525f4baecbac59c0a57125b1a5e356df9d295d657",
"boatstack/internal/deliverycontrol/coding_test.go": "58ba20bc4b1ca97f841523b73075dc953598263cd888f1d13c24e081fb0f8750",
"boatstack/internal/deliverycontrol/codinglog.go": "35cc491c1684b064cb260b0b6e889bc64f9f416a2a300dfb6ac5bccb2188ec8b",
"boatstack/internal/deliverycontrol/cost.go": "a0a22292b8ed55cbfce9808599449d5128ae5b67ef6adc4881e604db0897f3f0",
"boatstack/internal/deliverycontrol/graph.go": "13367b068d0004e0f2e857e7b6e9d19e758ef345070b3fbc008644be27438902",
"boatstack/internal/deliverycontrol/liveness.go": "23601670005085c62b9e7f4bd7eab74f340d622b2d80588f5cc90126307c8a8a",
"boatstack/internal/deliverycontrol/liveness_test.go": "7a148075d9d2c5df468fecb710bdd38226c4cd4b37584a810b6848909a0f3292",
"boatstack/internal/deliverycontrol/oracle.go": "80765b1946d6c863f0e635a99b68d3ccafa7ff235360fba774811b5b0de791da",
"boatstack/internal/deliverycontrol/oracle_test.go": "ce320a71f0c9440c5a7bc1b742d0f74c6a46759845e919ab36bde5ff8fabb311",
"boatstack/internal/deliverycontrol/registry.go": "aa89cef9eec8d715c06d2f61a472df20bb9334c950a6d751a1e15d67b567c433",
"boatstack/internal/deliverycontrol/registry_test.go": "473ab5e5d33f84d34c29a219db867abfc6eb3ad4489f3d5d0c7dc09b06d193f3",
"boatstack/internal/deliverycontrol/state.go": "2551624bbcbd8f9dd897a1e2240cef2cc1895d117a4030525d88f1d62f6e395e",
"boatstack/internal/deliverycontrol/trajectory.go": "e25eeb092fb2255bd82477141d5b094627c1d779bef3616b89752046ae08e7c3",
"boatstack/internal/deliverycontrol/trajectory.go": "4469a0c35b40f8e2a37060e9b26fcbda7d34d020088c31de367dd5cf6e7721dc",
"boatstack/internal/deliverycontrol/trajectory_test.go": "df5be9a8f55b09a94b0f6b94d2847180d39d357619eb4d1d11181015935c2f96",
"boatstack/internal/deliverycontrol/trajectorylog.go": "a1da7e7252b33f63f232c101de683b4a515e80243801caf69fda53d24233e42f",
"boatstack/internal/deliverycontrol/trajectorylog_test.go": "227dd6ed9ce181d517a37b67ef4d64dd93779a533eae804798ab54de35c7f13e",
Expand Down Expand Up @@ -151,10 +167,10 @@
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
"docs/configuration.md": "df054f49d532c8b1b7d94184810d1b3b5bf18cdc30eb985b4b6d0639162e341a",
"docs/evidence-engineered-coding.md": "bc8fcd561d1bc57f0cdbe79c537143e005b00995cbc8fe690982d00efdaf64d5",
"docs/evidence-engineered-coding.md": "e42fd1e704cc9d60d7fcb79c53e248944caf4984b02df1c496aceec5a5e51072",
"docs/generated-files.md": "437791765b0a4015032ae21d1a6618563cad92b7402819e4f963bf5ae16284a3",
"docs/getting-started.md": "1dd4f4e2e636cc5adfc2f79939629701e171087c3d5e558cf919548b9224adfd",
"docs/public-claims.json": "476511c6c2b2c4159f507b4e9c8f2c726b8a08a004db51a0967e73e92439050a",
"docs/public-claims.json": "52529747f11523647ca794a4d992008537e51d473935cf644144f95a4207603d",
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
"docs/research-and-design.md": "8d78678108f0a6c924e1ff9b32c0f81aae9d1f779e0082843b6f99ad993ae2b6",
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
Expand All @@ -168,7 +184,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": "2a120ef6977a3e028e66c534244d9cfcf5a347cde3738ad176038b6c57a1c370",
"labs/diagram-json/plan.lock.json": "30ac25c13348433f4be8c4f3df06b51431a434b427ddd6d1f4f26f14ad550f6c",
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
Expand Down Expand Up @@ -252,7 +268,11 @@
"release-notes/2026-07-25-boatstack-banner.md": "28e83f294de606211cfdc91b2586aa834e004dee76d5c4bee08859986ae86b5b",
"release-notes/2026-07-25-delivery-control-inventory.md": "1f359bcf4071dd47bd1011c877db573bd26309d28683abea8389c353f1c6c88d",
"release-notes/2026-07-25-delivery-flow-navigation-model.md": "b2d805fae30100a7de4e76760341247237cc2476fdcc57d99074825bf47d6450",
"release-notes/2026-07-25-deliverycontrol-coding-telemetry.md": "a229c737bfc9cc5ceddf109c246c41f00619e8a3fef0e0e78870e4255131741b",
"release-notes/2026-07-25-deliverycontrol-flow-check-advisory.md": "80ffb0fb64958d41f0b05fb3ef25ad464e63d1bc8021561c7360827859b6da77",
"release-notes/2026-07-25-deliverycontrol-flow-control.md": "4aeb013d9f0c54370a364b5fc9ee3aa30ec305d00ab77575b873bc1fd8da6ebf",
"release-notes/2026-07-25-deliverycontrol-flow-oracle.md": "04e64e27638b32a90a132f615f896bf20ee805f3c75bf5e3ab088f3c55e641a7",
"release-notes/2026-07-25-deliverycontrol-flow-report.md": "86c519e7debd72362f8ef6ef21ec443912aa705669f396259ba771303925bbb5",
"release-notes/2026-07-25-deliverycontrol-shadow-registry.md": "e7f8ca4e4f188eda3088e46cba77369d8ff0d903f29e43846103d986e79a2273",
"release-notes/2026-07-25-evidence-path-resolution.md": "b32cb8a6e69f397f751c3a7fb62be254a7407a28bed25ae9108d6d773c863d11",
"release-notes/2026-07-25-published-slice-correction-routing.md": "129cdd62c80c8b93060726027d68ba3abdb0bca1a1ce9e64d6053271af3fd082",
Expand All @@ -261,7 +281,7 @@
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
"schema_version": 1,
"source": {
"commit": "fac1f242bb58f88e94da3f7cbb50ba6159d02790",
"commit": "eec4b62c152cc2da37579f891706640bff9cb1a6",
"path": "labs/12-product-engineering-loop",
"repository": "operatorstack/intelligence-flow"
}
Expand Down
108 changes: 108 additions & 0 deletions boatstack/cmd/boatstack-helper/flow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import (
"flag"
"fmt"
"os"

boatstack "github.com/operatorstack/boatstack/boatstack"
)

// flowCommand is the read-only entry point for delivery-flow navigation:
// `flow check` gates the owned model, `flow next` advises the lowest-cost next
// move. Both are additive and side-effect free; they change no existing command,
// gate, authority, or exit code.
func flowCommand(arguments []string) int {
if len(arguments) == 0 {
fmt.Fprintln(os.Stderr, "usage: boatstack-helper flow <check|next|report>")
return 2
}
switch arguments[0] {
case "check":
return flowCheckCommand(arguments[1:])
case "next":
return flowNextCommand(arguments[1:])
case "report":
return flowReportCommand(arguments[1:])
default:
fmt.Fprintln(os.Stderr, "unknown flow subcommand:", arguments[0])
return 2
}
}

// flowCheckCommand runs the static conformance + liveness gate over the delivery
// model and exits non-zero on drift. It reads no repository state.
func flowCheckCommand(arguments []string) int {
flags := flag.NewFlagSet("flow check", flag.ContinueOnError)
jsonOutput := flags.Bool("json", false, "print the structured check result")
if err := flags.Parse(arguments); err != nil {
return 2
}
result := boatstack.FlowCheck()
if *jsonOutput {
value, err := boatstack.MarshalJSON(result)
if err != nil {
return fail(err)
}
fmt.Print(string(value))
} else {
fmt.Print(boatstack.FormatFlowCheck(result))
}
if !result.OK {
return 1
}
return 0
}

// flowNextCommand advises the lowest-cost next move toward a published delivery.
// It is purely advisory and never fails on flow position — an unresolved flow
// still prints the authoritative recommendation.
func flowNextCommand(arguments []string) int {
flags := flag.NewFlagSet("flow next", flag.ContinueOnError)
repo := flags.String("repo", ".", "repository whose delivery flow should be advised")
feature := flags.String("feature", "", "optional specific managed feature to advise")
jsonOutput := flags.Bool("json", false, "print the structured advisory")
if err := flags.Parse(arguments); err != nil {
return 2
}
next, err := boatstack.NextControl(*repo, *feature)
if err != nil {
return fail(err)
}
if *jsonOutput {
value, marshalErr := boatstack.MarshalJSON(next)
if marshalErr != nil {
return fail(marshalErr)
}
fmt.Print(string(value))
} else {
fmt.Print(boatstack.FormatFlowNext(next))
}
return 0
}

// flowReportCommand renders the session's flow-navigation regret and coding-effort
// telemetry from the shadow logs. It is read-only and never fails on an empty
// session — it simply reports zero steps.
func flowReportCommand(arguments []string) int {
flags := flag.NewFlagSet("flow report", flag.ContinueOnError)
repo := flags.String("repo", ".", "repository whose flow session should be reported")
jsonOutput := flags.Bool("json", false, "print the structured report")
if err := flags.Parse(arguments); err != nil {
return 2
}
report, err := boatstack.FlowReport(*repo)
if err != nil {
return fail(err)
}
if *jsonOutput {
value, marshalErr := boatstack.MarshalJSON(report)
if marshalErr != nil {
return fail(marshalErr)
}
fmt.Print(string(value))
} else {
fmt.Print(boatstack.FormatFlowReport(report))
}
return 0
}
28 changes: 23 additions & 5 deletions boatstack/cmd/boatstack-helper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,14 @@ func recordDeliveryGateCommand(arguments []string) int {
if options.Feature == "" || options.SliceID == "" || options.Gate == "" || options.Status == "" {
return fail(fmt.Errorf("record-delivery-gate requires --feature, --slice, --gate, and --status"))
}
transition := boatstack.GateTransition(options.Gate)
guard := boatstack.GuardFlowMove(options.Repo, options.Feature, transition)
if !guard.Allow {
boatstack.RecordFlowTransition(options.Repo, guard.Transition, guard.From, false)
return fail(fmt.Errorf("%s", guard.Message))
}
receipt, err := boatstack.RecordDeliveryGate(options)
boatstack.RecordFlowTransition(options.Repo, transition, guard.From, err == nil)
if err != nil {
return fail(err)
}
Expand Down Expand Up @@ -768,6 +775,9 @@ func recordChangeCommand(arguments []string) int {
if err != nil {
return fail(err)
}
// A recorded correction is the honest moment coding rework is initiated;
// record one unit of coding effort as telemetry (never a gate, never J_flow).
boatstack.RecordCodingEffort(options.Repo, 1, string(observation.Classification))
fmt.Printf("PASS: change observation recorded\nOBSERVATION_ID=%s\nCLASSIFICATION=%s\nOUTCOME=%s\nMODE=%s\nRESUME_STAGE=%s\n", observation.ID, observation.Classification, observation.Outcome, state.Mode, state.ResumeStage)
if observation.Outcome == "CORRECTIVE_CHILD_REQUIRED" {
fmt.Printf("PARENT_DELIVERY=%s\nSUGGESTED_FEATURE_ID=%s\n", observation.ParentDelivery, observation.SuggestedFeatureID)
Expand Down Expand Up @@ -1088,10 +1098,20 @@ func publishPRCommand(arguments []string) int {
if *previewPath == "" || *fingerprint == "" || *action == "" {
return fail(fmt.Errorf("publish-pr requires --preview, --preview-fingerprint, and --action"))
}
feature := ""
if preview, previewErr := boatstack.ParsePRPreview(*previewPath); previewErr == nil {
feature = preview.Feature
}
guard := boatstack.GuardFlowMove(*repo, feature, boatstack.PublishTransition)
if !guard.Allow {
boatstack.RecordFlowTransition(*repo, guard.Transition, guard.From, false)
return fail(fmt.Errorf("%s", guard.Message))
}
url, err := boatstack.PublishPR(boatstack.PRPublishOptions{
Repo: *repo, PreviewPath: *previewPath, ExpectedFingerprint: *fingerprint, Action: *action,
VisualPublisher: boatstack.SelectVisualPublisher(*repo),
})
boatstack.RecordFlowTransition(*repo, boatstack.PublishTransition, guard.From, err == nil)
if err != nil {
return fail(err)
}
Expand All @@ -1101,10 +1121,6 @@ func publishPRCommand(arguments []string) int {
}
fmt.Printf("PASS: PR %s without merge authorization\nPR_URL=%s\n", verb, url)

feature := ""
if preview, err := boatstack.ParsePRPreview(*previewPath); err == nil {
feature = preview.Feature
}
if update, ok := boatstack.PostShipUpdateNotice(*repo, feature); ok {
fmt.Printf("UPDATE_AVAILABLE=%s\nUPDATE_RELEASE_URL=%s\n", update.LatestVersion, update.ReleaseURL)
}
Expand Down Expand Up @@ -1205,7 +1221,7 @@ func workspaceSyncCommand(arguments []string) int {

func run() int {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: boatstack-helper <init|update|check-update|repair-status|operation-status|prepare-update-pr|publish-update-pr|release-classify|next-patch|export|check-source-plan|planning-write|check-plan|record-approval|activate-plan|delivery-status|next-status|recovery-status|repair-state|mutation-status|undo|run-preflight|record-change|ignore-delivery|record-delivery-gate|record-pr-visual-evidence|capture-evidence|provision-capability|capability-register|record-pr-visual-publication|check-safety|migrate-config|safety-hook|diagnose-hook|pr-context|check-pr|publish-pr|workspace-cut|workspace-cleanup|workspace-status|workspace-sync|doctor|version>")
fmt.Fprintln(os.Stderr, "usage: boatstack-helper <init|update|check-update|repair-status|operation-status|prepare-update-pr|publish-update-pr|release-classify|next-patch|export|check-source-plan|planning-write|check-plan|record-approval|activate-plan|delivery-status|next-status|recovery-status|repair-state|mutation-status|undo|run-preflight|record-change|ignore-delivery|record-delivery-gate|record-pr-visual-evidence|capture-evidence|provision-capability|capability-register|record-pr-visual-publication|check-safety|migrate-config|safety-hook|diagnose-hook|pr-context|check-pr|publish-pr|workspace-cut|workspace-cleanup|workspace-status|workspace-sync|flow|doctor|version>")
return 2
}
switch os.Args[1] {
Expand Down Expand Up @@ -1299,6 +1315,8 @@ func run() int {
return workspaceSyncCommand(os.Args[2:])
case "migrate-config":
return migrateConfigCommand(os.Args[2:])
case "flow":
return flowCommand(os.Args[2:])
case "version":
fmt.Printf("Boatstack %s (%s)\n", boatstack.Version, boatstack.SourceCommit)
return 0
Expand Down
Loading
Loading