Conversation
…rontmatter - MEMORY_CATEGORIES["knowledge"] gains "decisions" slot; memory init lazy-creates knowledge/decisions/.gitkeep via existing directory loop - New optional fields: decision_status (proposed | accepted | superseded enum), superseded_by, alternatives_considered (inline list) - MEMORY_FIELD_ORDER carries explicit slots after applies_when so writes are deterministic across repeated read+write cycles - validate_memory_frontmatter enum-checks decision_status; argparse choices on --decision-status give cli-level rejection too (belt + braces) - ci_test.sh decisions-track section: round-trip of all three optional fields, invalid decision_status rejected (cli + validator), deterministic write order across two cycles, lazy-dir-create assertion on memory init - smoke_test.sh placeholder count 5 → 6 + explicit decisions/.gitkeep check - memory README template lists decisions/ + new decision-specific optional fields Task: fn-38-project-glossary-decision-records-and.1
- Add `flowctl glossary {add,list,read,remove}` subcommands
- `find_nearest_glossary` walks cwd → repo root, bounded at git root,
filesystem boundary (st_dev change), 32-level defensive cap; never
manually follows symlinks (kernel handles ELOOP)
- `parse_glossary_file` masks fenced code byte-for-byte (spaces in
place of non-newlines) so heading offsets stay aligned with the
original text — fenced `## not a heading` lines are not picked up
- `render_glossary_file` always emits `# Glossary` H1 husk so the
last-term-removal path leaves a recognizable file (R18: project
state, never delete)
- `add` writes to nearest-ancestor (matches read resolution); creates
at repo root when no ancestor exists; force a subdir glossary by
dropping an empty `GLOSSARY.md` first (no `--scope` flag per spec)
- `--definition-file -` reads stdin; `--definition-file <path>` reads
file; mutually exclusive with `--definition`
- Case-insensitive term match for update + read + remove; whitespace-
collapsed compare
- New `glossary_smoke_test.sh` (80 cases): bare repo, single-line
roundtrip, multi-line stdin, mutex flags, empty-input rejection,
case-insensitive update, multi-term insertion order, subdir-wins,
ancestor-fallback, repo-root cutoff, 32-level depth cap, atomic-write
crash simulation, parse roundtrip, _Avoid_ + _Relates to_ roundtrip,
term removal, husk hygiene, fenced-code stripping, R18 (.flow/
removal), R4 (no meta-file), R17 (no DDD jargon in help), R15
(markdown shape), JSON shape
Task: fn-38-project-glossary-decision-records-and.2
Includes T1 plan-sync drift updates to .flow/tasks/...1.md + ...8.md
(memory-scout knowledge-category enumeration drift surfaced by T1
worker; updated by plan-sync but not yet committed).
…cs, four behaviors) - Husk-aware autodetect via `glossary list --json | jq .total_terms` + decisions count - `--docs` forces on (lazy-creates root GLOSSARY.md), `--no-docs` forces off - Behavior (a) phase-zero glossary scan with load-bearing throttle - Behavior (b) fuzzy-term sharpening writes via `glossary add --definition-file -` - Behavior (c) code-vs-assertion contradiction surfaces via AskUserQuestion - Behavior (d) decision-record write with three-criteria gate + read-back - Glossary-lookup as third Pre-Question Taxonomy axis - New `## Glossary Conflicts` spec section - R17 clean: no DDD jargon in canonical or Codex mirror - sync-codex.sh validation green: no AskUserQuestion leak, all openai.yaml present Task: fn-38-project-glossary-decision-records-and.3
- Scan list adds `flowctl glossary list --json` (raw `find` fallback) + `.flow/memory/knowledge/decisions/`. Husk groups (count: 0) skipped. - Mapping table gains "Glossary term touched" + "Decision constraint" rows. - Output example shows term + decision-id flags surfacing. - Codex mirror regenerated via sync-codex.sh (clean). - R17: no DDD jargon. Task: fn-38-project-glossary-decision-records-and.4
- Phase 0.5 (new) — enumerate GLOSSARY.md via flowctl glossary list --json;
per term, grep tracked code for term + _Avoid_ aliases (case-insensitive,
whole-word, normalized whitespace); zero hits + zero alias hits → mark stale
via Edit-tool HTML comment after term heading (no flowctl glossary mark-stale
exists post-T2); alias hits → alias-creep finding for Phase 3 / report; husk
files (count: 0) get a single advisory, never deleted.
- Decisions auto-walked — MEMORY_CATEGORIES knowledge:decisions extension
(T1) means the existing glob picks up knowledge/decisions/*.md without a
new phase. Documented in workflow.md §0.1.
- Decision-entry calibration in phases.md — judging question shifts to "does
the constraint that motivated this decision still hold?"; Replace becomes a
two-step supersession (write new entry; edit old's decision_status:
superseded + superseded_by; never git rm).
- Phase 5 report grows a Glossary section (Files scanned / Terms scanned /
Kept / Marked stale / Alias-creep flagged) plus per-term detail and husk
advisories.
- SKILL.md Forbidden block: explicit prohibitions on git-rm'ing superseded
decisions, deleting glossary terms, mass code renames from alias-creep,
inventing flowctl glossary mark-stale.
- Codex mirror regenerated via sync-codex.sh (zero errors; Claude-native
AskUserQuestion → request_user_input rewrite intact; no DDD vocabulary).
Verification:
- ./scripts/sync-codex.sh — clean
- audit_smoke_test.sh — 41/41 PASS (no regression)
- glossary_smoke_test.sh — 80/80 PASS (no regression)
- R17 grep guard (ubiquitous language|bounded context|domain expert|
aggregate root) across plugins/flow-next/{skills,agents,commands,codex} +
flowctl.py — RC=1 (clean)
Task: fn-38-project-glossary-decision-records-and.5
Earlier flowctl done absorbed T4's stale /tmp evidence files because the Write tool refused to overwrite them. Replace with the actual T5 commit (ffd9535) + actual T5 test commands.
Sync skill (Step 5/6) now gathers `flowctl glossary list --json` and `flowctl memory list --track knowledge --category decisions --json`, passing both as `GLOSSARY_JSON` / `DECISIONS_JSON` to the plan-sync agent. Plan-sync agent gains Phase 3b: - 3b.1 glossary-term renames: when a downstream/old spec uses an `_Avoid_` alias and the new code uses the canonical term, update the spec (replaces alias, leaves a `<!-- Updated by plan-sync: glossary rename ... -->` breadcrumb). Reuses `_glossary_term_matches` semantics (case-insensitive + whitespace-collapsed). - 3b.2 decision overrides: when completed-task code touches files referenced in an active decision's `Consequences` section in a way that contradicts the decision, surface the decision id in the summary under "Decision overrides flagged for review". Read-only — no auto-supersession (user/audit handles that). Husks (`count: 0`) and superseded decisions are skipped — no signal. Both context inputs are best-effort with empty defaults so the agent prompt stays valid when flowctl returns nothing or fails. Codex mirror regenerated. R17 clean. Smoke suites unchanged: 130 + 80 + 41 + 94 + 58 + 74 pass. Task: fn-38-project-glossary-decision-records-and.6
ci_test.sh: add 5c "Plugin-source hygiene" block scanning
plugins/flow-next/{skills,agents,commands,scripts/flowctl.py} for
R17 forbidden vocabulary and R4 meta-file references; failure
prints offending file:line.
sync-codex.sh: extend validation block with mirror-scoped R17 +
R4 grep guards alongside the existing AskUserQuestion / ToolSearch
hygiene check; failure increments errors and prints count +
remediation hint. Two-tier mirror keeps the mirror's invariants the
sync script's responsibility.
Verified: both tiers pass on current canonical + mirror; injecting
a fixture in skills/flow-next/ trips canonical guard (file:line
breadcrumb) and propagates through sync to trip the mirror guard
(3 R17 hits + 1 R4 hit, exit 1).
Task: fn-38-project-glossary-decision-records-and.7
…ware interview - CHANGELOG.md: new [flow-next 0.39.0] block (Added / Changed / Notes) - CLAUDE.md: interview commands list + memory block (decisions category + decision-specific fields) + new Glossary section after Prospecting - README.md (root): version badge bump + what's-new callout to v0.39.0 - plugins/flow-next/README.md: version badge, what's-new, TOC, memory tree (decisions/), decisions frontmatter schema, audit + sync extension notes, docs-gap-scout note, interview doc-aware mode + Glossary Conflicts template section, commands table interview row, autonomous flag table interview row, new Project Glossary section - .flow/usage.md: new Glossary subcommand block - plugins/flow-next/docs/flowctl.md: available-commands list adds glossary, memory category enumeration adds decisions + decision-specific fields, new ### glossary section with subcommands + JSON shapes + husk semantics - plugins/flow-next/agents/memory-scout.md:22 — knowledge category list appends decisions (caught by T1 plan-sync) - .flow/specs/fn-38-...md:238 — fix husk-aware autodetect example to use flowctl glossary list --json | jq '.total_terms > 0' instead of plain [[ -f GLOSSARY.md ]] (caught by T2 plan-sync) - plugins/flow-next/codex/agents/memory-scout.toml — regenerated by scripts/sync-codex.sh R17 + R4 grep guards both green (canonical ci_test.sh section 5c + sync-codex.sh mirror validation). 56 ci_test, 130 smoke, 80 glossary smoke all pass. No mickel.tech changes (maintainer-only per CLAUDE.md). Task: fn-38-project-glossary-decision-records-and.8
Task: fn-38-project-glossary-decision-records-and.8
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 527b9da4c7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for stripped_match in (avoid_match, relates_match): | ||
| if stripped_match is not None: | ||
| def_text = ( | ||
| def_text[: stripped_match.start()] | ||
| + def_text[stripped_match.end() :] | ||
| ) |
There was a problem hiding this comment.
Strip glossary metadata lines without stale match offsets
When an entry includes both _Avoid_ and _Relates to_, parse_glossary_file mutates def_text twice using match indices captured from the original body; after the first splice, the second match offsets are no longer valid. Because render_glossary_file writes _Avoid_ before _Relates to_, this common path leaves a truncated _Relates to fragment in definition, so subsequent glossary read/list/add/remove round-trips corrupt the stored definition text.
Useful? React with 👍 / 👎.
Summary
GLOSSARY.mdat repo root — new project canonical-vocabulary file withflowctl glossary {add,list,read,remove}subcommands, nearest-ancestor walk (tsconfig-style first-match-wins, ceiling at git repo root, 32-level cap),_Avoid_aliases, multi-line definitions via--definition-file -. Survivesrm -rf .flow/because terminology is the project's, not flow-next's.knowledge/decisions/memory category — extends categorized memory schema withdecision_statuslifecycle (proposed → accepted → superseded),superseded_by,alternatives_considered. 1-3 sentence body floor;Considered Options+Consequencesoptional. Indexed bymemory-scout, walked by/flow-next:audit./flow-next:interview— autodetects when glossary has terms (husks ignored viatotal_terms > 0) or decisions/ is non-empty.--docs/--no-docsoverride. Four behaviors: glossary lookup before terminology questions (writes## Glossary Conflictsspec section), inline glossary write on resolution, decision-record prompt with three-criteria gate + read-back, code/spec contradiction surfaced not silently overwritten.docs-gap-scoutscansGLOSSARY.md+knowledge/decisions/./flow-next:auditPhase 0.5 walks glossary terms (greps code, marks stale on absence, surfaces alias-creep) + Phase 0.1 auto-walks decisions (supersede-not-delete Replace)./flow-next:syncPhase 3b detects glossary renames (rewrite via_Avoid_aliases) and flags decision overrides read-only (never auto-supersedes).ci_test.shsection 5c (file:line breadcrumbs), mirror scan insync-codex.shvalidation block (count + remediation hint). Catches DDD vocabulary leakage and meta-file references in both source-of-truth and Codex mirror.Test plan
plugins/flow-next/scripts/ci_test.sh— 56/56 pass (was 47, +9 for decisions track + R17/R4 guards)plugins/flow-next/scripts/smoke_test.sh— 130/130 passplugins/flow-next/scripts/glossary_smoke_test.sh— 80/80 pass (new — 25 cases including nearest-ancestor walk, atomic writes, multi-line stdin, fenced-code stripping, husk hygiene, R18 verification)plugins/flow-next/scripts/audit_smoke_test.sh— 41/41 pass (no regression)plugins/flow-next/scripts/prospect_smoke_test.sh— 94/94 pass (no regression)scripts/sync-codex.sh— clean (21 skills, 21 agents, all 14 requiredopenai.yaml, R17 + R4 mirror guards green)/flow-next:interviewdoc-aware autodetect: empty repo → off, one term added → on, husk-after-remove → off (R18 verified bytotal_terms > 0check), decisions-only → onGLOSSARY.mdround-trip (add→read→remove) in a fresh repoflowctl glossary readresolves nearest-ancestor when run from a subdirectory with its ownGLOSSARY.md/flow-next:auditPhase 0.5 surfaces_Avoid_alias creep when an alias appears in codeR-IDs
R1-R18 all satisfied (R18 added during planning to make uninstall-survival testable). Coverage table in
.flow/specs/fn-38-project-glossary-decision-records-and.md.Out of scope (deferred)
Subdir-scoped
--scope hereflag, slug normalization for special characters, danglingsuperseded_byref validation, concurrent-write coordination beyond atomic single-call writes, file-watching cache invalidation, auto-generated glossary-from-code, decision-supersession workflow onaudit(surfaces only).🤖 Generated by
/flow-next:workfrom epic spec at.flow/specs/fn-38-project-glossary-decision-records-and.md