Repository navigation
T20 — Scaffold and append entries with min init - #2962
minimal-foundry[bot] wants to merge 12 commits into
Conversation
min init now writes minimal.toml in the entry shape: [defaults.session], [defaults.task] and a [boxes.dev] session entry. min init <entry> --type <type> appends one [boxes.<entry>] entry. --session, --task, --agent and --service are aliases for --type with that noun. More than one of them, or one with --type, ends with exit 2 and the file unchanged. A type that is, or extends, agent, service, build or container-build ends with exit 3. The activate scaffold offer keeps the legacy shape, because this tree does not read entries at activation yet.
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
|
Reviewed: 1 finding, none blocking at Address the comments on the diff. Clobber: none seen in the touched files. |
There was a problem hiding this comment.
arch-review: CONDITIONS · 3 conditions · the full ruling
The scaffold shape and the append conform to architecture.md line 448 and lines 1173–1176. A refusal ends the process with std::process::exit inside the root span. The spool records a span only when it ends, so D9 (line 793) loses the refused outcome. C1 routes the exit code through failure_exit_code and adds cmd/mod.rs and main.rs to the layers. init_request accepts self and names that are not DNS-safe, against line 1176. C2 refuses them with exit 2. C3 links the legacy-shape interim to an issue with a flip condition. The escalation asks whether BCLI-017 can merge before the BOX reader of [defaults.session].
Outside the diff
crates/minimal/src/cmd/mod.rs:294: C1 · This arm formats the error to a string, and theInitRefusaltype is lost. Mapmctx::Error::Other(e)toe, and format only the other variants.crates/minimal/src/main.rs:208: C1 · Add a branch: whene.downcast_ref::<minimal::InitRefusal>()matches, returnrefusal.codeasu8. Add a test for exit 2 and exit 3.
Ruled at 5c90f9d against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Held by the maintainer: this waits on BOX T15 (#2409), which reads |
|
/revise Head 1. C1: a refusal must end through Delete 2. C2: entry names (architecture line 1176, Addressing line 390). In 3. C3: the two-shape interim is no longer needed. Remove it. C3 asked for an issue for the BOX reader of |
…nd-append-entries-with-min-init
cmd_init returns an InitRefusal as its error, so the cmd span closes and its outcome record reaches the spool. failure_exit_code in main.rs gives the refusal's code (2 or 3). exit_refused is gone. min init refuses the entry name self, and a name that is not a DNS label, with exit 2 before it reads any file. The activate scaffold stays in the legacy shape: session start does not read [defaults.session] yet. The comment names #2410 as the flip.
…nd-append-entries-with-min-init
There was a problem hiding this comment.
arch-review: CONDITIONS · 3 conditions · the full ruling
The compare fixes the exit path. Refusals now end through failure_exit_code, and the cmd span closes. Three exit codes still do not agree with the design. Line 1176 makes self, a name that is not DNS-safe, and a duplicate name invalid minimal.toml, and line 364 gives exit 3 for that. mfile::entry already uses 3. C1 and C2 change check_entry_name and the duplicate check to code 3, and C2 also replaces ENTRY_TABLES with EntryTable::ALL. C3 makes a [box_types] entry with no extends exit 3, as line 1232 states.
Ruled at af34c8a against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 1 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
Notes from the agent: The branch already contained origin/main (merge 1a65936 includes #3091), so no new merge was necessary. C1 and C2 are done as the directive asks. cmd/mod.rs and main.rs are outside layers:, and the directive names them. InitRefusal.code is now u8, because failure_exit_code returns u8. INIT_ONE_TYPE_FLAG is now pub so that the main.rs test can use it. C3 is NOT done as the directive asks, on purpose. The premise is that the reader of [defaults.session] is on main. It is not. #3091 adds mfile::entry::read_entries, which nothing outside mfile calls. It reads only the entry tables. mfile::File still has no [defaults.session]: that key lands in Defaults.extra and logs 'unknown fields in [defaults]'. Session start reads packages only from the legacy [session]. If the activate scaffold flips to the entry shape, a plain |
|
/revise Head 1. C1: an invalid entry name is a minimal.toml error, exit 3. In 2. C2: a duplicate entry name exits 3, and the table list has one owner. In 3. C3: a In Also add one line to the PR body, before the notes: |
|
Marked ready by the BCLI babysitter, with the owner's approval. The runtime drafted this PR because |
An entry name that is self or not DNS-safe, a duplicate entry name, and a [box_types] entry with no extends make minimal.toml invalid, so min init refuses them with exit 3. The duplicate check reads the entry tables from mfile::entry::EntryTable::ALL.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 9 unresolved threads — minimal-arch[bot] crates/minimal/src/cmd/project.rs, minimal-arch[bot] crates/minimal/src/cmd/project.rs, minimal-arch[bot] crates/minimal/src/cmd/project.rs:532, minimal-foundry[bot] crates/minimal/src/cmd/project.rs:839, minimal-arch[bot] crates/minimal/src/cmd/project.rs, …. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The compare resolves the open conditions. An invalid entry name, self, a duplicate name and a [box_types] entry with no extends now exit 3. This agrees with design lines 1176 and 1232 and the exit-code table. The flag conflicts stay exit 2, as line 448 states. The duplicate check now uses mfile::entry::EntryTable::ALL, so mfile owns the table list. Two residuals stay open: #2410 for reading [defaults.session], and gominimal/inbox#579 for organization types.
Ruled at 127ec0e against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 2 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
Notes from the agent: Revise round 2 did only the three ruling-1014 items. C1: check_entry_name returns code 3 for |
There was a problem hiding this comment.
minimal-review — approved
Verdict APPROVE — every review thread is resolved; @agent-137 closed the last one. The review of 127ec0ee8d8f withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.
|
Round 3 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review.
Notes from the agent: Residual for the PR body, before the notes: BCLI-017's entry-shape scaffold is built and tested, but How I did it: |
|
/revise Head 1. Thread PRRT_kwDOPdfcxM60qlds (LOW): the scaffold span names an entry the file lacks.
2. Thread PRRT_kwDOPdfcxM60qldo (MEDIUM): This is the owner's decision, so do not change it. Reply on the thread: on The PR body still shows the round-0 notes, which describe the removed |
…nd-append-entries-with-min-init
The legacy [session] scaffold has no dev entry, so the span records shape = "legacy" and leaves entry out while INIT_ENTRY_SHAPE is false.
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
BCLI-018 and the exit codes are unchanged, and the PASS on 127ec0e stands for them. Bare min init now writes the legacy [session] table. The design's minimal.toml layout (lines 1165 and 1173) and its canonical example have no such table. The interim is honest and its reason is true: box creation does not merge [defaults.<type>] yet. C1 is the flip when #2418 lands, and it stays open as that residual. Also update the PR body's Proof section. It still says that min init writes the entry shape.
Ruled at f2efb84 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 4 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
Notes from the agent: Round 4 changes only the scaffold tracing record in cmd_init (commit f2efb84). It records shape = "legacy" and leaves out entry while INIT_ENTRY_SHAPE is false. The append records keep entry = . No other behaviour changed. BCLI-017's default entry-shaped scaffold is not on by default. That is the owner's decision, and it waits on #2418. |
|
/revise Head
Reply on the thread with the commit. |
…nd-append-entries-with-min-init
min init <entry> --type <type> now locates the project's minimal.toml with mfile::File::from_dir_recursive, the search the other commands use, so it works from a project subdirectory. With --repo-dir it looks in that directory only, as MFileSearchStrategy::Override does. Both layouts in one directory are refused with exit 3, and the message names both paths.
There was a problem hiding this comment.
arch-review: CONDITIONS · 1 condition · the full ruling
The new search for minimal.toml conforms to the Discovery line (architecture.md line 1167). But mfile::File::from_dir now parses the file before the append. A minimal.toml that does not parse now exits 1 through the generic error arm in find_init_mfile. The Exit codes table (line 364) gives 3 for invalid configuration, and this head gave 3 for that file before this commit. Make the change in C1. Then the change conforms.
Ruled at 5cf31ba against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 5 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
Notes from the agent: Revise round 5, commit 5cf31ba. find_init_mfile now calls mfile::File::from_dir_recursive without --repo-dir (MFileSearchStrategy::CurrentDirRecursive), and mfile::File::from_dir with --repo-dir (MFileSearchStrategy::Override). mfile::Error::ConflictingLayouts becomes an InitRefusal with code 3 that names both paths. NotFound stays code 1, and its message adds 'or its parent directories' when the search walks up. Other mfile errors (for example a parse error) are now reported before the append, with the context 'reading minimal.toml'. The bare scaffold is unchanged and still writes to the current directory. New tests: init_entry_type_appends_from_subdirectory and init_conflicting_layouts_exit3_appends_nothing. cargo clippy -p minimal --all-targets is clean. just clippy-strict was not run. |
|
/revise Head C1: a In
Add the test |
A minimal.toml that does not parse or validate is invalid configuration. min init now refuses it with exit 3, names the file, and leaves it unchanged. An I/O error still exits 1.
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The compare fixes the open point from 5cf31ba. A minimal.toml that does not parse or validate now refuses min init <entry> --type <type> with exit 3, names the file and changes nothing. That agrees with the exit-code table, line 364. An I/O error stays exit 1. BCLI-018 conforms. The BCLI-017 interim from f2efb84 is still open and filed on #2418. C1 is its flip, and it can stay open at merge.
Ruled at bef69e7 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 6 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
Notes from the agent: C1 is done. In find_init_mfile, mfile::Error::IO stays on the generic exit-1 path. Every other mfile::Error is now InitRefusal { code: 3 }. The message is: "min init did not add the entry: is not valid. Fix the file, then run the command again." The mfile error follows on a new line, because the toml parse error prints on several lines. mfile::Error::Format does not carry the file path. So a new helper in project.rs, located_init_mfile, finds the path with the same search that mfile::File::from_dir and from_dir_recursive use, including the stop at HOME. The new test init_invalid_mfile_exit3_appends_nothing runs from the project root and from a subdirectory. I did not change anything else. |
There was a problem hiding this comment.
Babysitter review at bef69e74. No blocking findings. The approval is left to the owner, because agent-137 wrote this PR's /revise directives and body residuals.
- BCLI-018:
min init <entry> --type <t>(and the noun-flag aliases, which exclude each other with exit 2) appends one[boxes.<entry>]to theminimal.tomlfound by the same ancestor search the other commands use. Both layouts present is refused with exit 3, naming both paths. - Refusals return through
main.rsfailure_exit_code: exit 2 for usage, and exit 3 for invalidminimal.toml(a bad or reserved name, a duplicate, a[box_types]entry withoutextends, an unparsable file). An I/O error stays exit 1. Each refusal leaves the file unchanged, and tests pin that. - BCLI-017: the entry-shape scaffold is built and tested but off by default (
INIT_ENTRY_SHAPE = false) until #2418. Baremin initwrites the legacy shape that session start reads today. The flip is recorded on #2418. - Residuals in the body: the #2418 flip, the effect of appended entries, and the
cmd/mod.rsedit outsidelayers:.
T20 — Scaffold and append entries with min init
slice: S5
kind: task
covers: BCLI-017, BCLI-018
size: L
est: 200 code, 300 tests
executor: agent
difficulty: routine
model: standard
diagnostics: when two of
--session,--task,--agent,--serviceand--typeare given,min initprints "Pass one of --session, --task, --agent, --service or --type." and changes nothing, pinned by init_noun_flags_exclusive_exit2_appends_nothingobservability: the command's existing tracing span records the verb, the box id it resolved and the outcome
layers:
- client:
- crates/minimal/src/cli.rs: the verb's arguments and help in the one command model
- crates/minimal/src/cmd/project.rs:
min initscaffolds the entry shape and appends one entry by--typeor a noun flagtest: cargo nextest run -p minimal init_scaffolds_entry_shape
test: cargo nextest run -p minimal init_entry_type_appends_one
test: cargo nextest run -p minimal init_refused_type_exit3_appends_nothing
test: cargo nextest run -p minimal init_noun_flag_is_type_alias
test: cargo nextest run -p minimal init_noun_flags_exclusive_exit2_appends_nothing
produces: none
consumes: none
proof:
min initwrites an entry-shapedminimal.toml, andmin init <entry> --type <type>appends one entry.Residuals
min initwith no flags writes the legacy[session]shape (INIT_ENTRY_SHAPE = false). Onmain, box creation does not read[defaults.<type>]yet, so an entry-shaped scaffold would lose its packages at session start. BOX T21 (T21 — One minimal.toml for every box, end to end #2418) wiresmfile::expandinto box creation. When T21 — One minimal.toml for every box, end to end #2418 lands,min initandoffer_mfile_scaffoldwrite the entry shape, and theentry_shapeparameter is removed. The owner decided this on 2026-11-06.[boxes.*].min init <entry> --type <type>(BCLI-018) writes[boxes.<entry>]and reports it. Onmain,min session startstill reads[session], andmin task runstill reads[tasks]. Until T21 — One minimal.toml for every box, end to end #2418 (BOX T21) wires entry expansion into box creation, an appended entry is in the file but no command creates a box from it. The owner decided on 2026-11-06 to ship the append with this residual.crates/minimal/src/cmd/mod.rsis outside T20'slayers:. Arch ruling 808 C1 required the change so that anInitRefusalreachesfailure_exit_code.min initwrites the entry shape, that is superseded: at this head, baremin initwrites the legacy[session]shape (see the first residual), andinit_no_flags_writes_legacy_shapepins it.main.rsfailure_exit_code(exit 2 for usage, 3 for invalidminimal.toml), andexit_refusedis gone.Proof
min initnow writes minimal.toml in the entry shape: [defaults.session] with the packages, [defaults.task] with state_key, and a [boxes.dev] entry with type = "session".min init <entry> --type <type>appends one [boxes.] entry and keeps the rest of the file.min init --session <n>(also --task, --agent, --service) writes the same file asmin init <n> --type <noun>. If you give more than one of these flags, min init prints "Pass one of --session, --task, --agent, --service or --type.", exits 2 and changes nothing. A type that is, or extends, agent, service, build or container-build is refused with exit 3 and changes nothing.Notes from the agent: 1. Exit codes: crates/minimal/src/cmd/mod.rs turns every cmd_init error into a string, so main.rs can only give exit 1. mod.rs and main.rs are outside the layers. For this reason cmd_init prints its refusal and calls std::process::exit with the code (2 or 3) itself. The tests check the code on the InitRefusal value and do not run the binary. A later task can route this through failure_exit_code. 2. Nothing in this tree reads [boxes.*], [defaults.session] or [defaults.task] yet. mfile logs them as unknown fields. So a project scaffolded by
min initgets no session packages from minimal.toml at activation until the BOX entry expansion lands. For this reason the scaffold offer inmin activate(offer_mfile_scaffold) keeps the legacy [session] shape. run_init_flow takes a new entry_shape flag for this. 3. Choices the spec does not fix: appended entries go under [boxes.] with type. An unknown type, an entry with no type, or --type with no entry exits 2. A duplicate entry name in boxes/sessions/tasks/agents/services exits 1. A missing minimal.toml exits 1 and tells the user to run min init first. Project types resolve through the [box_types.] extends chain to a built-in root. 4. The exit-3 refusal names gominimal/inbox#678 because BOX-063 requires it. That is an issue reference, not a co…[truncated]Tests
cargo nextest run -p minimal init_scaffolds_entry_shapecargo nextest run -p minimal init_entry_type_appends_onecargo nextest run -p minimal init_refused_type_exit3_appends_nothingcargo nextest run -p minimal init_noun_flag_is_type_aliascargo nextest run -p minimal init_noun_flags_exclusive_exit2_appends_nothingVerify
min task run agent-verifyexited 100 under rustc 1.99.0, which the repository does not pin (1.99.1 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.Closes #2893