Skip to content

Commit bd2ab12

Browse files
Sync Boatstack from Intelligence Flow Labs @ 8d4cb2c8cac6 (#67)
Co-authored-by: operator-stack-publisher[bot] <operator-stack-publisher[bot]@users.noreply.github.com>
1 parent 6db1884 commit bd2ab12

11 files changed

Lines changed: 428 additions & 36 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/b0d1c2855e04be6f85e16b8e8d5bdd3cbd74fd10/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/8d4cb2c8cac6176823cebcd13ba9bd1d2791d2e9/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

README.md

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,9 @@ Receipts remain as history; published corrections become linked deliveries.
133133

134134
</details>
135135

136-
### Optional changelog
136+
## Configure repository policy
137137

138-
It is disabled by default. Enable it in `.boatstack-project.json`:
139-
140-
```json
141-
{
142-
"workflow": {
143-
"maintain_changelog": true
144-
}
145-
}
146-
```
147-
148-
Enabled repositories require a categorized `CHANGELOG.md``Unreleased` entry for every managed slice and Boatstack-prepared ad-hoc PR. The file stays user-owned; install and update never overwrite it. [See the format and first-entry example](docs/getting-started.md#keep-a-repository-changelog).
138+
`.boatstack-project.json` controls the project commands and context Boatstack uses, which coding hosts it supports, and opt-in policies for changelogs, boundary analysis, high-risk review, and feature workspaces. [Choose the outcomes you want and see every configuration field](docs/configuration.md).
149139

150140
## How Boatstack fits into your AI stack
151141

UPSTREAM.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
},
1313
"files": {
1414
".gitignore": "a7079e923a776f14f1bb3a6aa0a11a133a8e1dfb35af020f327623357b7e3957",
15-
"CONTRIBUTING.md": "927f0a25406086d3d014e024b6754f9a64fc792edcaced2fbf58e2671a034bbf",
16-
"README.md": "2a8ed9e1b3305d68d6a6aba68b78a6301daa29acc15a53f805ac94551326cce8",
15+
"CONTRIBUTING.md": "8eb2f460f13deea678b1862c2705f56a186a2e00d9abb3fe7448f16272f18cc6",
16+
"README.md": "1b8b3dea6186faa18f01afa096117c57e2bd0b1c4765f35ef87518018e3839e0",
1717
"assets/boatstack-journey.svg": "e465befc50c8ce30f3e07e8fd97012931beeb053392c8fbf38ad645023b3cc63",
1818
"assets/boatstack-mark.svg": "be1f984da1bfa69fa5d1f986d8343d21f7e20921b71db888c928b4d2e54b09b5",
1919
"assets/boatstack-portability.svg": "66dfdfa85db857b3bd18b32047a6975f1fbbfc4dc091158e8277193f9969a346",
@@ -36,6 +36,7 @@
3636
"boatstack/changelog_test.go": "ce792f23a7fe1e09fb3096cd1314130a6ab69321d4877b12a8e994027541baf7",
3737
"boatstack/cmd/boatstack-helper/main.go": "91f869e9dd8b9b19a07c161e170f720ef4d51bc7fba67606d66cf973fcf0422f",
3838
"boatstack/cmd/boatstack-helper/main_test.go": "ff73003b6a5157202fa09ddf1129fb13c3d79702b2e05a8721ce5a11bf5ab779",
39+
"boatstack/config_documentation_test.go": "109f2c8550c695db6ff0eb2bd1d24856d0f5af2e36c78de11819d6016062c97b",
3940
"boatstack/decision.go": "257ca328da6ae19ab252f10ee5d06bd7daf49dd8141d083ab1b32f106ea7a94c",
4041
"boatstack/decision_test.go": "1a92ff832610f9559bd47ccac7fc1755a8b4f8261c35bc72a092830dff05f7c0",
4142
"boatstack/delivery.go": "6ff71b6f4ae4f85a184edaf453b5933a79366e36137802fda056e58f83fe319c",
@@ -64,7 +65,7 @@
6465
"boatstack/pr.go": "b076ac9e05978b90bf6063209f6ab75bbe2bcd8b9bf38c62ad3ba7b1e2d59e83",
6566
"boatstack/pr_test.go": "ae23130d9d96cf214cf272227aa572dd09e2fe3adac22921949f541ba99ecb23",
6667
"boatstack/references/artifacts.md": "8f2e79b8af4bd3ad2e32aa3e8c07f10812555d0a3247e4991db75cc1cda395c3",
67-
"boatstack/references/config-schema.md": "894c001601246ad87411756902aa7b2962314e4395e2075f94d5c7c93c99e013",
68+
"boatstack/references/config-schema.md": "9ece0ac49290e5d213e573ca68290996eb81b2b25e68bcfc93a77130cea2ab6e",
6869
"boatstack/references/failure-moves.md": "1d35126348d0b681976e8819665e16fd745fd65eca271492603cb80aab75bf49",
6970
"boatstack/references/host-hook-contracts.md": "1382213ad004389de6da5a03af43ec28ace6329c9e7a3f07148566cf2ea12727",
7071
"boatstack/references/irreversible-operation-boundary.md": "631743991ace65977586e4537f8dd50f8ae88f8e16f27cf7baad93b2791a73df",
@@ -91,10 +92,11 @@
9192
"docs/account-recovery-walkthrough.md": "676034974594a7d1a559b24dbed31d7ccc429eb81404b203ca07bbdaa19ec3d3",
9293
"docs/benchmark-corpus-audit.md": "f2d206fe8579a514f9da82b2c96c19b343ac004be67617e1bd34f0f8e0e5e6c6",
9394
"docs/benchmark-submission-audit.md": "9518abdd17690729c6423f87cab20418ed47b0915b5faa44b9ef975e9e9c3b79",
94-
"docs/evidence-engineered-coding.md": "d785365deb036d5e4ec783abd4b0ce04488faa17ff5de279b0293e0b7325da70",
95+
"docs/configuration.md": "010863ef7a772c0a2f813651ce8ca4c605c91474b7ebd42cc76902e6737021b6",
96+
"docs/evidence-engineered-coding.md": "4aa0901f596afcba3552d2ff7a5a46a4959b7c1e29558f402be65b3ea01dc75b",
9597
"docs/generated-files.md": "136422baf0c7fc2bd5100cfe0ebdb3d9d0705dfd7e7d54bf745dd1037e63492c",
9698
"docs/getting-started.md": "eacc814fdffdfa3c7d8052b7cd99a79c04da5c75d88d8b44f3fb68d9afec0316",
97-
"docs/public-claims.json": "2528752e111bf8c626435356fdc62535c23e3f1c8512639ef23f74b0cc87fe1a",
99+
"docs/public-claims.json": "773712cb5afd6a167cfa68076beac1090234cbdae2af461992a0754b595b0b34",
98100
"docs/public-surface.md": "713f7a050b5f339cf948299103ef3800417dccfecf2cc1a4166397ea6f978907",
99101
"docs/research-and-design.md": "d65c66e323037bda5d45aacef5d48afa6bf93da55901378891d235aca3a5684f",
100102
"docs/safety.md": "7b9b5c515d36e683767ec8d3d9d6d119ac93650b2f629d351deadd4c600ed6a6",
@@ -108,7 +110,7 @@
108110
"labs/diagram-json/compiled/evidence.md": "1ba1c989ade070a8ef9a508fbd788d100d7292f2dbacbb2bce895468019f619d",
109111
"labs/diagram-json/compiled/tasks.json": "88f60851abf79d851e9fccc754ff3040034ae595306bc87d64784c19eb403e71",
110112
"labs/diagram-json/compiled/test-matrix.json": "424657ff505768e50fa113801fd8363364a18269d5297480907a993d44063a39",
111-
"labs/diagram-json/plan.lock.json": "7c07e8bd6c6c69bc1955e0621895e23274af54d483e650964ab93e3aa39ca9d6",
113+
"labs/diagram-json/plan.lock.json": "2af3449918001fbac5b71dd4b7a53cd64b7f1982a6798be9afb76f8f0d2cbebb",
112114
"labs/diagram-json/plan.md": "3cc4f533b8d69386deff16b3a594a3ba09d4c0c3db636cccd8c4380084ce6a51",
113115
"labs/diagram-json/questions.md": "74733b015002c8a6777c558e7e997fa48c94850b9bd39054fe9366c97ecf728d",
114116
"labs/diagram-json/request.md": "0808fc41c36779c404f4a3a121167da6e76cac56df526e70f9ed6d3e0d4c02ed",
@@ -158,12 +160,14 @@
158160
"release-notes/2026-07-21-value-translation-readme.md": "8dd16fd08c1591667a1074fc6825dcbf58beda0faa18ede1526647267418c8ea",
159161
"release-notes/2026-07-22-boundary-analysis-dx.md": "60d727ab3b109fff95a82eb36ee4c6c5833760535b14f386fda349a21b4fe588",
160162
"release-notes/2026-07-22-boundary-oracle-loop.md": "698c2ed7dd0a000e6e210f521989992b8fa476376987819ba92c12feb3528f7c",
163+
"release-notes/2026-07-22-product-configuration-guide.md": "45e96862336bd53a2628ce3fe718c829ea20315555f53187eb7f04ba749f3a97",
164+
"release-notes/2026-07-22-projection-layout-validation.md": "fd0d2935f3f0c4caa41bda678e3bd9a9b496eb2652ab38d80c1c1434cbba3159",
161165
"release-notes/2026-07-22-value-translation-boundary.md": "9cf168ff7caaf3906b78533935bdfb2c86e753984ed1e5ec8204cb373d083390"
162166
},
163167
"generator": "operatorstack/intelligence-flow:boatstack-distribution",
164168
"schema_version": 1,
165169
"source": {
166-
"commit": "b0d1c2855e04be6f85e16b8e8d5bdd3cbd74fd10",
170+
"commit": "8d4cb2c8cac6176823cebcd13ba9bd1d2791d2e9",
167171
"path": "labs/12-product-engineering-loop",
168172
"repository": "operatorstack/intelligence-flow"
169173
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package boatstack
2+
3+
import (
4+
"os"
5+
"reflect"
6+
"sort"
7+
"strings"
8+
"testing"
9+
)
10+
11+
const configFieldMarkerPrefix = "boatstack-config-field:"
12+
13+
func configSurface(value reflect.Type, prefix string) []string {
14+
if value.Kind() == reflect.Pointer {
15+
value = value.Elem()
16+
}
17+
var fields []string
18+
for index := 0; index < value.NumField(); index++ {
19+
field := value.Field(index)
20+
name := strings.Split(field.Tag.Get("json"), ",")[0]
21+
if name == "" || name == "-" {
22+
continue
23+
}
24+
path := name
25+
if prefix != "" {
26+
path = prefix + "." + name
27+
}
28+
fields = append(fields, path)
29+
30+
nested := field.Type
31+
if nested.Kind() == reflect.Pointer {
32+
nested = nested.Elem()
33+
}
34+
switch nested.Kind() {
35+
case reflect.Struct:
36+
fields = append(fields, configSurface(nested, path)...)
37+
case reflect.Map:
38+
item := nested.Elem()
39+
if item.Kind() == reflect.Struct {
40+
fields = append(fields, configSurface(item, path+".*")...)
41+
}
42+
}
43+
}
44+
return fields
45+
}
46+
47+
func configFieldMarkers(content string) []string {
48+
var fields []string
49+
for _, line := range strings.Split(content, "\n") {
50+
line = strings.TrimSpace(line)
51+
if strings.HasPrefix(line, configFieldMarkerPrefix) {
52+
fields = append(fields, strings.TrimPrefix(line, configFieldMarkerPrefix))
53+
}
54+
}
55+
sort.Strings(fields)
56+
return fields
57+
}
58+
59+
func documentedConfigSurface(t *testing.T, path string) []string {
60+
t.Helper()
61+
content, err := os.ReadFile(path)
62+
if err != nil {
63+
t.Fatalf("read configuration documentation %s: %v", path, err)
64+
}
65+
return configFieldMarkers(string(content))
66+
}
67+
68+
func publicConfigurationDocument(t *testing.T) string {
69+
t.Helper()
70+
candidates := []string{
71+
"../boatstack-distribution/CONFIGURATION.md",
72+
"../docs/configuration.md",
73+
}
74+
var found []string
75+
for _, candidate := range candidates {
76+
_, err := os.Stat(candidate)
77+
switch {
78+
case err == nil:
79+
found = append(found, candidate)
80+
case os.IsNotExist(err):
81+
continue
82+
default:
83+
t.Fatalf("inspect public configuration document %s: %v", candidate, err)
84+
}
85+
}
86+
if len(found) != 1 {
87+
t.Fatalf("expected exactly one public configuration document from %v, found %v", candidates, found)
88+
}
89+
return found[0]
90+
}
91+
92+
func TestConfigFieldMarkersAcceptWindowsLineEndings(t *testing.T) {
93+
content := "<!--\r\nboatstack-config-field:project.name\r\nboatstack-config-field:workflow\r\n-->\r\n"
94+
want := []string{"project.name", "workflow"}
95+
if got := configFieldMarkers(content); !reflect.DeepEqual(got, want) {
96+
t.Fatalf("CRLF configuration markers were not parsed: got %v, want %v", got, want)
97+
}
98+
}
99+
100+
func TestPublicConfigurationSurfaceIsDocumented(t *testing.T) {
101+
want := configSurface(reflect.TypeOf(ProjectConfig{}), "")
102+
sort.Strings(want)
103+
104+
for _, document := range []string{
105+
"references/config-schema.md",
106+
publicConfigurationDocument(t),
107+
} {
108+
got := documentedConfigSurface(t, document)
109+
if !reflect.DeepEqual(got, want) {
110+
t.Errorf("configuration documentation drift in %s\nimplementation: %v\ndocumented: %v", document, want, got)
111+
}
112+
}
113+
}

boatstack/references/config-schema.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# Boatstack Configuration Schema
22

3+
<!--
4+
boatstack-config-field:schema_version
5+
boatstack-config-field:project
6+
boatstack-config-field:project.name
7+
boatstack-config-field:project.default_branch
8+
boatstack-config-field:project.context
9+
boatstack-config-field:project.commands
10+
boatstack-config-field:project.high_risk_paths
11+
boatstack-config-field:workflow
12+
boatstack-config-field:workflow.human_plan_approval
13+
boatstack-config-field:workflow.independent_review_for_high_risk
14+
boatstack-config-field:workflow.allow_pass_with_gaps
15+
boatstack-config-field:workflow.maintain_changelog
16+
boatstack-config-field:workflow.boundary_analysis
17+
boatstack-config-field:workspace
18+
boatstack-config-field:workspace.enabled
19+
boatstack-config-field:workspace.mode
20+
boatstack-config-field:workspace.cleanup
21+
boatstack-config-field:workspace.cleanup_after
22+
boatstack-config-field:adapters
23+
boatstack-config-field:integrations
24+
boatstack-config-field:integrations.*.requested
25+
boatstack-config-field:integrations.*.status
26+
boatstack-config-field:integrations.*.version
27+
boatstack-config-field:integrations.*.detail
28+
-->
29+
330
This reference document defines the schema and version history of `.boatstack-project.json`.
431

532
## Current Schema Version
@@ -13,6 +40,7 @@ This reference document defines the schema and version history of `.boatstack-pr
1340
- `schema_version` (integer, required): Must be exactly `1`.
1441
- `project` (object, required): General project definition.
1542
- `workflow` (object, required): Flags controlling state machine transitions and safety gates.
43+
- `workspace` (object, optional): Opt-in per-feature branch or worktree management.
1644
- `adapters` (array of strings, optional): Enabled host environment adapters. If empty, defaults to enabling all.
1745
- `integrations` (object, optional): Explicit configurations for individual third-party integrations.
1846

@@ -23,17 +51,39 @@ This reference document defines the schema and version history of `.boatstack-pr
2351
- `context` (array of strings, optional): Paths to persistent project directories or contextual documents.
2452
- `commands` (object, required): Custom development commands:
2553
- `test` (string, required): The exact command to execute project-local tests.
54+
- Other command names (string, optional): Additional repository-owned commands such as `build`, `lint`, or `typecheck`.
2655
- `high_risk_paths` (array of strings, optional): Glob patterns of files requiring independent reviewer sign-off before shipping.
2756

2857
### workflow Fields
2958

3059
- `human_plan_approval` (boolean, optional): Whether a parent plan requires explicit human approval before building.
3160
- `independent_review_for_high_risk` (boolean, optional): Whether modifications to high-risk files require a distinct peer review gate.
3261
- `allow_pass_with_gaps` (boolean, optional): Whether the delivery verification allows outstanding questions or gaps.
33-
- `maintain_changelog` (boolean, optional): Whether a release-notes fragment is required for each delivery slice.
62+
- `maintain_changelog` (boolean, optional): Whether a reader-visible `CHANGELOG.md` entry is required for each delivery slice.
63+
- `boundary_analysis` (boolean, optional): Whether planning checks for a missing systemic boundary and presents local repair versus programmatic enforcement as a material product decision.
64+
65+
### workspace Fields
66+
67+
- `enabled` (boolean, optional): Enables managed per-feature workspaces. Defaults to `false`.
68+
- `mode` (string, optional): `worktree` or `branch`. Defaults to `worktree` when workspace management is enabled.
69+
- `cleanup` (string, optional): `confirm`, `auto`, or `off`. Defaults to `confirm`.
70+
- `cleanup_after` (string, optional): `merge` or `ship`. Defaults to `merge`.
71+
72+
### adapters Values
73+
74+
Supported values are `cursor`, `claude`, `codex`, `gemini`, and `github`. An empty or omitted array enables all supported adapters.
75+
76+
### integrations Fields
77+
78+
Supported integration keys are `gstack` and `spec-kit`. Each integration state can contain:
79+
80+
- `requested` (boolean, required when the integration is present): Whether installation was requested.
81+
- `status` (string, optional): Installer-maintained installation status.
82+
- `version` (string, optional): Installer-maintained pinned version or revision.
83+
- `detail` (string, optional): Installer-maintained diagnostic detail.
3484

3585
## Version Changelog
3686

3787
### Version 1
3888

39-
- Initial schema with `project`, `workflow`, `adapters`, and `integrations`.
89+
- Initial schema with `project`, `workflow`, `workspace`, `adapters`, and `integrations`.

0 commit comments

Comments
 (0)