devflow-kit 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +479 -1
- package/README.md +15 -15
- package/dist/agents/code.md +6 -8
- package/dist/agents/design.md +1 -1
- package/dist/agents/fix.md +7 -8
- package/dist/agents/git.md +3 -3
- package/dist/agents/harden.md +1 -1
- package/dist/agents/refactor.md +2 -4
- package/dist/agents/review.md +4 -4
- package/dist/agents/skim.md +2 -2
- package/dist/agents/triage.md +9 -2
- package/dist/cli/commands/capture.js +1 -1
- package/dist/cli/commands/curation-move-io.js +102 -0
- package/dist/cli/commands/curation-move-step.js +374 -0
- package/dist/cli/commands/curation.js +808 -0
- package/dist/cli/commands/gate-level-prompts.js +428 -0
- package/dist/cli/commands/gates.js +35 -11
- package/dist/cli/commands/init-seed.js +11 -8
- package/dist/cli/commands/init.js +244 -57
- package/dist/cli/commands/memory.js +60 -13
- package/dist/cli/commands/prompt-io.js +37 -0
- package/dist/cli/commands/uninstall.js +157 -17
- package/dist/cli.js +2 -2
- package/dist/commands/bug-analysis.md +25 -36
- package/dist/commands/code-review.md +40 -44
- package/dist/commands/debug.md +5 -5
- package/dist/commands/dynamic-build.md +26 -25
- package/dist/commands/dynamic-plan.md +5 -5
- package/dist/commands/dynamic-profile.md +5 -5
- package/dist/commands/dynamic-tickets.md +5 -5
- package/dist/commands/explore.md +6 -6
- package/dist/commands/implement.md +53 -82
- package/dist/commands/plan.md +6 -6
- package/dist/commands/release.md +5 -5
- package/dist/commands/research.md +6 -6
- package/dist/commands/resolve.md +39 -41
- package/dist/commands/self-review.md +5 -13
- package/dist/core/area-pause-notice.js +44 -0
- package/dist/core/assets.js +20 -20
- package/dist/core/curate-tuning-config.js +5 -6
- package/dist/core/curation-move-notice.js +84 -0
- package/dist/core/curation-move-skip.js +35 -0
- package/dist/core/curation-move.js +35 -0
- package/dist/core/curation-queue-cleanup.js +135 -0
- package/dist/core/curation-store.js +99 -0
- package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
- package/dist/core/echo-value.js +11 -5
- package/dist/core/evidence-policy.js +11 -9
- package/dist/core/feature-switch.js +95 -19
- package/dist/core/fs-atomic.js +1 -1
- package/dist/core/gate-level.js +10 -2
- package/dist/core/git.js +16 -14
- package/dist/core/ledger-root.js +82 -22
- package/dist/core/linked-path.js +4 -4
- package/dist/core/manifest-lock.js +238 -0
- package/dist/core/manifest.js +58 -14
- package/dist/core/migrations.js +1 -13
- package/dist/core/observations.js +2 -2
- package/dist/core/plugins.js +19 -19
- package/dist/core/pool.js +26 -0
- package/dist/core/project-paths.js +103 -34
- package/dist/core/queue-drain.js +2 -2
- package/dist/core/tracked-areas.js +159 -0
- package/dist/core/tracker.js +1 -1
- package/dist/{learning-off → curation-off}/agents/code.md +6 -8
- package/dist/{learning-off → curation-off}/agents/fix.md +7 -8
- package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
- package/dist/{learning-off → curation-off}/agents/review.md +3 -3
- package/dist/{learning-off → curation-off}/agents/triage.md +8 -1
- package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
- package/dist/{learning-off → curation-off}/commands/code-review.md +37 -41
- package/dist/{learning-off → curation-off}/commands/debug.md +2 -2
- package/dist/{learning-off → curation-off}/commands/dynamic-build.md +23 -22
- package/dist/{learning-off → curation-off}/commands/explore.md +2 -2
- package/dist/{learning-off → curation-off}/commands/implement.md +50 -79
- package/dist/{learning-off → curation-off}/commands/plan.md +2 -2
- package/dist/{learning-off → curation-off}/commands/resolve.md +36 -38
- package/dist/{learning-off → curation-off}/commands/self-review.md +2 -10
- package/dist/hud/components/{learning-counts.js → curation-counts.js} +63 -17
- package/dist/hud/config.js +1 -1
- package/dist/hud/index.js +6 -6
- package/dist/hud/render.js +3 -3
- package/dist/skills/git/references/pr/post-resolution-summary.md +12 -11
- package/dist/skills/git/references/pr/post-review-summary.md +12 -11
- package/dist/skills/git/references/pr/update-pr-evidence.md +2 -2
- package/dist/skills/git/references/pr/validate-branch.md +8 -5
- package/dist/skills/git/references/publication-gate.md +6 -7
- package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/github/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/jira/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
- package/dist/skills/git/references/tracker/linear/manage-debt.md +6 -2
- package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
- package/dist/targets/claude-code/installer.js +15 -15
- package/dist/targets/claude-code/language-stamp.js +5 -5
- package/dist/targets/claude-code/post-install.js +2 -2
- package/dist/targets/claude-code/tracker-servers.js +1 -1
- package/package.json +3 -2
- package/src/assets/agents/_partials/_code.mds +11 -11
- package/src/assets/agents/code.mds +6 -6
- package/src/assets/agents/curate.md +8 -8
- package/src/assets/agents/debug.mds +6 -6
- package/src/assets/agents/design.mds +18 -18
- package/src/assets/agents/evaluate.md +6 -12
- package/src/assets/agents/fix.mds +7 -6
- package/src/assets/agents/git.mds +3 -3
- package/src/assets/agents/harden.mds +7 -7
- package/src/assets/agents/knowledge.mds +23 -23
- package/src/assets/agents/refactor.mds +2 -2
- package/src/assets/agents/research.mds +15 -15
- package/src/assets/agents/review.mds +43 -43
- package/src/assets/agents/skim.mds +11 -11
- package/src/assets/agents/triage.mds +29 -22
- package/src/assets/agents/validate.md +30 -50
- package/src/assets/commands/_partials/_decisions.mds +22 -20
- package/src/assets/commands/_partials/_engine.mds +8 -8
- package/src/assets/commands/_partials/_knowledge.mds +29 -15
- package/src/assets/commands/_partials/_preamble.mds +4 -4
- package/src/assets/commands/_partials/_settings.mds +3 -3
- package/src/assets/commands/_partials/_wave.mds +7 -7
- package/src/assets/commands/bug-analysis.mds +37 -48
- package/src/assets/commands/code-review.mds +53 -57
- package/src/assets/commands/debug.mds +14 -14
- package/src/assets/commands/dynamic-build.mds +38 -37
- package/src/assets/commands/dynamic-plan.mds +22 -22
- package/src/assets/commands/dynamic-profile.mds +2 -2
- package/src/assets/commands/dynamic-tickets.mds +8 -8
- package/src/assets/commands/explore.mds +20 -20
- package/src/assets/commands/implement.mds +77 -98
- package/src/assets/commands/plan.mds +27 -27
- package/src/assets/commands/release.mds +12 -12
- package/src/assets/commands/research.mds +19 -19
- package/src/assets/commands/resolve.mds +66 -60
- package/src/assets/commands/self-review.mds +20 -20
- package/src/assets/mds/git/_ops.mds +9 -2
- package/src/assets/mds/git/_ops_pr.mds +21 -11
- package/src/assets/mds/git/_ops_steps.mds +20 -4
- package/src/assets/mds/git/_pr.mds +21 -18
- package/src/assets/mds/git/_references.mds +6 -7
- package/src/assets/mds/tracker/_github.mds +1 -4
- package/src/assets/mds/tracker/_jira.mds +1 -4
- package/src/assets/mds/tracker/_linear.mds +1 -4
- package/src/assets/rules/quality.md +1 -0
- package/src/assets/scripts/ci-wait.cjs +389 -92
- package/src/assets/scripts/hooks/background-memory-update +81 -3
- package/src/assets/scripts/hooks/capture-prompt +12 -12
- package/src/assets/scripts/hooks/capture-question +11 -11
- package/src/assets/scripts/hooks/capture-turn +12 -12
- package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
- package/src/assets/scripts/hooks/curation-move +293 -0
- package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
- package/src/assets/scripts/hooks/ensure-proxy +4 -4
- package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
- package/src/assets/scripts/hooks/git-marker +81 -0
- package/src/assets/scripts/hooks/json-helper.cjs +176 -51
- package/src/assets/scripts/hooks/json-parse +1 -1
- package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
- package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +308 -122
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
- package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +42 -22
- package/src/assets/scripts/hooks/lib/tracked-areas.cjs +452 -0
- package/src/assets/scripts/hooks/memory-permission +10 -2
- package/src/assets/scripts/hooks/memory-worker +12 -1
- package/src/assets/scripts/hooks/pre-compact-memory +17 -16
- package/src/assets/scripts/hooks/queue-append +444 -102
- package/src/assets/scripts/hooks/resolve-project-root +2 -2
- package/src/assets/scripts/hooks/session-start-context +198 -72
- package/src/assets/scripts/hooks/session-start-memory +42 -43
- package/src/assets/scripts/lib/project-config.cjs +12 -5
- package/src/assets/scripts/pr-evidence.cjs +5 -2
- package/src/assets/scripts/resolve-base.cjs +1043 -0
- package/src/assets/scripts/resolve-settings.cjs +283 -45
- package/src/assets/scripts/verify-evidence.cjs +307 -75
- package/src/assets/skills/agent-references/SKILL.md +11 -2
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +29 -0
- package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
- package/src/assets/skills/agent-references/references/commands/resolve-levels.md +25 -0
- package/src/assets/skills/agent-references/references/synthesize/review.md +4 -4
- package/src/assets/skills/agent-references/references/triage/severity-tiers.md +43 -0
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +14 -0
- package/src/assets/skills/apply-decisions/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +7 -7
- package/src/assets/skills/docs-framework/references/patterns.md +3 -4
- package/src/assets/skills/quality-gates/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/references/roots.md +2 -2
- package/templates/lint-pack/.lint-pack.conf +86 -0
- package/templates/lint-pack/README.md +190 -0
- package/templates/lint-pack/lint-pack.sh +905 -0
- package/dist/cli/commands/learning.js +0 -554
- package/dist/core/learning-queue-cleanup.js +0 -27
- package/dist/core/learning-store.js +0 -61
- /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
- /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
- /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
|
@@ -77,19 +77,19 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off>
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
90
90
|
### DECISIONS_CONTEXT — obtain BEFORE authoring
|
|
91
91
|
|
|
92
|
-
When the settings line says `
|
|
92
|
+
When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
|
|
93
93
|
|
|
94
94
|
The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
95
95
|
|
|
@@ -103,9 +103,9 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
|
|
|
103
103
|
2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
|
|
104
104
|
3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
|
|
105
105
|
|
|
106
|
-
This is the rule the
|
|
106
|
+
This is the rule the curation hooks apply, so you read the index the Curate agent writes.
|
|
107
107
|
|
|
108
|
-
Before you author the workflow script, read `{ledger}/.devflow/
|
|
108
|
+
Before you author the workflow script, read `{ledger}/.devflow/curation/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
|
|
109
109
|
|
|
110
110
|
The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into the prompts of the Code, Fix, Design, Knowledge, Review and Harden agents, which follow `devflow:apply-decisions`. Those are the agent types above whose contract declares it; every other agent type gets no decisions context.
|
|
111
111
|
|
|
@@ -307,7 +307,7 @@ TASK_DESCRIPTION: ${TICKET}
|
|
|
307
307
|
ISSUE_REQUIRED: ${ISSUE_REQUIRED}
|
|
308
308
|
APPLY_CONVENTIONS: ${APPLY_CONVENTIONS}
|
|
309
309
|
${ISSUE_INPUT !== "(none)" ? "ISSUE_INPUT: " + ISSUE_INPUT : ""}
|
|
310
|
-
Return: {"branch": "<the - **Branch name**: value under your ### Branch, or (none)>", "issueId": "<the - **Issue ID**: value under your ### Handoff Values, or (none)>", "prLinkLine": "<the - **PR link line**: value, or (none)>"}`, { agentType: "Git" })
|
|
310
|
+
Return: {"branch": "<the - **Branch name**: value under your ### Branch, or (none)>", "issueId": "<the - **Issue ID**: value under your ### Handoff Values, or (none)>", "prLinkLine": "<the - **PR link line**: value, or (none)>", "baseSha": "<the 40 or 64 hex git rev-parse HEAD prints before step 4>"}`, { agentType: "Git" })
|
|
311
311
|
);
|
|
312
312
|
|
|
313
313
|
// The ticket's own Handoff Values, read from setup-task's Output — never derived from ISSUE_INPUT.
|
|
@@ -317,6 +317,7 @@ const ISSUE_NUMBER = ISSUE_ID_SHAPE.test(String(setup?.issueId ?? "")) ? setup.i
|
|
|
317
317
|
const ISSUE_PR_LINK = setup?.prLinkLine || "(none)"; // "(none)" ⇒ the wave PR carries no closing reference for this ticket
|
|
318
318
|
// The branch setup-task created, as it reported it: every later phase and the merge use it. The engine never names one.
|
|
319
319
|
const BRANCH = typeof setup?.branch === "string" && setup.branch.trim() !== "" && setup.branch.trim() !== "(none)" ? setup.branch : "(none)";
|
|
320
|
+
const BASE_SHA = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(String(setup?.baseSha ?? "")) ? setup.baseSha : "(none)"; // the commit the ticket branch was forked from
|
|
320
321
|
|
|
321
322
|
// Ticket-link stop, before implement. The workflow cannot ask, so it never records an exception: it stops.
|
|
322
323
|
if (ISSUE_REQUIRED === "true" && ISSUE_NUMBER === "(none)") {
|
|
@@ -328,6 +329,11 @@ if (BRANCH === "(none)") {
|
|
|
328
329
|
return { ticket: TICKET, branch: BRANCH, verdict: "ESCALATED", issueId: ISSUE_NUMBER, issuePrLink: ISSUE_PR_LINK, escalations: [{ type: "branch-missing", description: "setup-task reported no branch name — check its Output, then re-run" }] };
|
|
329
330
|
}
|
|
330
331
|
|
|
332
|
+
// Base stop: every review range starts at the commit the ticket branch was forked from.
|
|
333
|
+
if (BASE_SHA === "(none)") {
|
|
334
|
+
return { ticket: TICKET, branch: BRANCH, verdict: "ESCALATED", issueId: ISSUE_NUMBER, issuePrLink: ISSUE_PR_LINK, escalations: [{ type: "base-missing", description: "setup-task reported no base commit — check its Output, then re-run" }] };
|
|
335
|
+
}
|
|
336
|
+
|
|
331
337
|
// Phase 2: Implement
|
|
332
338
|
await phase("implement", () =>
|
|
333
339
|
agent(`OPERATION: implement
|
|
@@ -447,10 +453,9 @@ Self-verify your fix compiles and the scenarios pass, following your Running com
|
|
|
447
453
|
|
|
448
454
|
// Phase 5: Review → verify → fix (single pass)
|
|
449
455
|
const reviewResult = await phase("review", async () => {
|
|
450
|
-
// Review scope: the entire branch diff from the
|
|
451
|
-
// Review agents diff the branch against its merge-base with the default branch.
|
|
456
|
+
// Review scope: the entire branch diff, from the commit the ticket branch was forked from to HEAD.
|
|
452
457
|
// The pass runs exactly ONCE.
|
|
453
|
-
const reviewScope = `Review the full branch diff on branch ${BRANCH}
|
|
458
|
+
const reviewScope = `Review the full branch diff on branch ${BRANCH}.\nDIFF_RANGE: ${BASE_SHA}...HEAD\n`;
|
|
454
459
|
|
|
455
460
|
// Review agent focus list (order = index mapping for dead-reviewer detection)
|
|
456
461
|
const reviewFocuses = ["security", "architecture", "performance", "complexity", "consistency", "regression", "testing", "reliability"];
|
|
@@ -494,13 +499,12 @@ Focus discipline: ${focus}. Return: {"focus": "${focus}", "reviewed": true, "fil
|
|
|
494
499
|
return { survivingFindings: [], fixedFindings: [], coverageGaps };
|
|
495
500
|
}
|
|
496
501
|
|
|
497
|
-
// Adversarial
|
|
498
|
-
// Panel asks perspective-diverse questions over the WHOLE finding set (not one agent per finding).
|
|
499
|
-
// A finding survives if >50% of panel agents CONFIRM it.
|
|
502
|
+
// Adversarial panel over the WHOLE finding set (not one agent per finding): >50% CONFIRMED survives
|
|
500
503
|
const VERIFY_PANEL = 3;
|
|
501
504
|
const panels = await parallel(
|
|
502
505
|
Array.from({ length: VERIFY_PANEL }, (_, lens) => () =>
|
|
503
506
|
agent(`Adversarially verify all ${allFindings.length} findings on branch ${BRANCH}.
|
|
507
|
+
DIFF_RANGE: ${BASE_SHA}...HEAD
|
|
504
508
|
Lens ${lens + 1} of ${VERIFY_PANEL}:
|
|
505
509
|
${["Does each finding actually reproduce in the current code? Hunt for findings that describe patterns not present in the diff.",
|
|
506
510
|
"Is each finding a real issue or a false positive in context? Consider intent, surrounding code, and project conventions.",
|
|
@@ -518,16 +522,13 @@ ${JSON.stringify(allFindings.map((f, i) => ({ index: i, description: f.descripti
|
|
|
518
522
|
panels.filter(p => (p.verdicts || []).find(v => v.index === i)?.verdict === "CONFIRMED").length > VERIFY_PANEL / 2
|
|
519
523
|
);
|
|
520
524
|
|
|
521
|
-
// No confirmed findings
|
|
525
|
+
// No confirmed findings: coverageGaps carry forward and block PASS downstream
|
|
522
526
|
if (confirmedFindings.length === 0) {
|
|
523
527
|
return { survivingFindings: [], fixedFindings: [], coverageGaps };
|
|
524
528
|
}
|
|
525
529
|
|
|
526
|
-
//
|
|
527
|
-
//
|
|
528
|
-
// concurrent same-file edits cause index contention and lost fixes).
|
|
529
|
-
// Sub-batches for DISTINCT files run in parallel (different code areas — safe per concurrency doctrine).
|
|
530
|
-
// A finding with no file field gets its own singleton group (unknown scope — never mix with known files).
|
|
530
|
+
// Sub-batches (max 5 findings): same file in sequence, distinct files in parallel.
|
|
531
|
+
// A finding with no file is a singleton group.
|
|
531
532
|
const MAX_BATCH = 5; // max 5 findings per sub-batch
|
|
532
533
|
const fileGroups = {};
|
|
533
534
|
for (let fi = 0; fi < confirmedFindings.length; fi++) {
|
|
@@ -537,9 +538,7 @@ ${JSON.stringify(allFindings.map((f, i) => ({ index: i, description: f.descripti
|
|
|
537
538
|
fileGroups[key].push(f);
|
|
538
539
|
}
|
|
539
540
|
|
|
540
|
-
// One entry per
|
|
541
|
-
// Distinct-file groups are paced in chunks of FIX_CHUNK — same pacing bar as the Review spawn
|
|
542
|
-
// path — to avoid launching all Code agents at once on a large branch (reliability: explicit bound).
|
|
541
|
+
// One entry per file; FIX_CHUNK chunks bound concurrent Code agents
|
|
543
542
|
const FIX_CHUNK = 5;
|
|
544
543
|
// issue-fix SCOPE per finding: CRITICAL or HIGH takes the Careful protocol (failing regression test first); anything else is Standard.
|
|
545
544
|
const CAREFUL_SEVERITIES = new Set(["critical", "high"]);
|
|
@@ -822,7 +821,7 @@ The review pass runs exactly ONCE per ticket. One full-branch review → one adv
|
|
|
822
821
|
|
|
823
822
|
**Step 1 — Spawn Review agents in parallel (one agent() per focus)**
|
|
824
823
|
|
|
825
|
-
**Review scope:** the entire branch diff
|
|
824
|
+
**Review scope:** the entire branch diff, `DIFF_RANGE: {base commit}...HEAD`; the base commit is the 40 or 64 hex commit that the ticket branch was forked from, as the setup step reported it; a ticket with none stops `base-missing`.
|
|
826
825
|
|
|
827
826
|
Core Review agents (always, 8 total): security, architecture, performance, complexity, consistency, regression, testing, reliability
|
|
828
827
|
|
|
@@ -905,7 +904,7 @@ Each ticket engine run returns a structured result. The Synthesize agent or the
|
|
|
905
904
|
},
|
|
906
905
|
"escalations": [
|
|
907
906
|
{
|
|
908
|
-
"type": "merge-conflict | gate2-fail | validation-exhausted | harden-blocked | ambiguous-resolution | review-coverage-incomplete | dependency-blocked | engine-crash | ticket-link-missing | branch-missing",
|
|
907
|
+
"type": "merge-conflict | gate2-fail | validation-exhausted | harden-blocked | ambiguous-resolution | review-coverage-incomplete | dependency-blocked | engine-crash | ticket-link-missing | branch-missing | base-missing",
|
|
909
908
|
"description": "string"
|
|
910
909
|
}
|
|
911
910
|
],
|
|
@@ -1050,7 +1049,7 @@ const results = {}; // ticketId → its row of the workflow's return
|
|
|
1050
1049
|
const rowOf = (ticketId, r, merged, treeEqual = null) => ({ ticket: ticketId, ran: true, verdict: r?.verdict || r?.overallVerdict || null, merged, treeEqual, issuePrLink: r?.issuePrLink || "(none)", evaluateVerdict: r?.gate2?.evaluateVerdict, testVerdict: r?.gate2?.testVerdict, surviving: r?.survivingFindings?.length, coverageComplete: r?.reviewCoverage?.complete });
|
|
1051
1050
|
const MAX_ROUNDS = Math.max(10, remainingTickets.length * 2 + 5); // heuristic; always finite
|
|
1052
1051
|
const MERGE_SHA = /^[0-9a-f]{40}$/; // a SHA as git prints it; with the checked branch, the only Git-reported values that reach a merge, Validate or undo prompt
|
|
1053
|
-
const BRANCH_NAME = /^(?![-#]|(?:@|(?:FETCH_|ORIG_|MERGE_)?HEAD)$)(?!.*\.\.)[A-Za-z0-9._/+@,#-]{1,200}$/; //
|
|
1052
|
+
const BRANCH_NAME = /^(?![-#]|(?:@|(?:FETCH_|ORIG_|MERGE_)?HEAD)$)(?!.*\.\.)[A-Za-z0-9._/+@,#-]{1,200}$/; // STRICT_NAME_RE's deliberate variant, less its origin/ refusal; the name enters git lines
|
|
1054
1053
|
// One ticket's merge, post-merge Validate and undo (D-WAVE-MERGE-VALIDATE: Git validates nothing).
|
|
1055
1054
|
const mergeValidateUndo = async (ticketId, engineResult) => {
|
|
1056
1055
|
if (typeof engineResult.branch !== "string" || !BRANCH_NAME.test(engineResult.branch)) return { kept: false, reason: "ticket branch name refused: not a plain git ref name", halted: null, treeEqual: null };
|
|
@@ -1219,12 +1218,14 @@ Do NOT ask questions mid-workflow — that is impossible (F4). The workflow only
|
|
|
1219
1218
|
|
|
1220
1219
|
7. **Wave PR evidence** — only when step 6 reported the wave PR, after it; it never blocks, and every outcome below goes into the run summary. Take `{n}` from step 6's `- **PR**: #{n}` line when `{n}` matches `^[1-9][0-9]{0,9}$` as a whole; no such line ⇒ record `TRACEABILITY: DEGRADED (wave PR number not captured)` and skip this step. `PR_TEST_PLAN_BLOCK` `(none)` ⇒ record `Wave evidence: skipped (no wave test plan)` and skip it.
|
|
1221
1220
|
|
|
1221
|
+
**Changed files.** Take `{base_ref}` from step 6's `- **Base ref**:` line; only when it is 40 or 64 lowercase hex, run `git -C "{integration worktree root}" diff --name-only --diff-filter=d {base_ref}...HEAD; echo "exit=$?"`. Unless it ran and printed `exit=0`, record `TRACEABILITY: DEGRADED (wave base unusable)` and skip this step.
|
|
1222
|
+
|
|
1222
1223
|
**(a) Test the wave.** Spawn one Test agent on the integration worktree with the wave test plan — the TP lines of the `## Test Plan` section step 3(b) wrote to `{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md`:
|
|
1223
1224
|
|
|
1224
1225
|
```
|
|
1225
1226
|
Agent(subagent_type="Test"):
|
|
1226
1227
|
"ORIGINAL_REQUEST: the merged tickets of wave/{slug}, as the wave test plan names them
|
|
1227
|
-
FILES_CHANGED: {the
|
|
1228
|
+
FILES_CHANGED: {the file list that diff printed}
|
|
1228
1229
|
TEST_PLAN: {the TP lines of the wave evidence file's ## Test Plan section}
|
|
1229
1230
|
WORKTREE_PATH: {integration worktree root}
|
|
1230
1231
|
Cover every TEST_PLAN line on the integration branch as it stands. Report PASS or FAIL with evidence."
|
|
@@ -77,19 +77,19 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off>
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
90
90
|
### DECISIONS_CONTEXT — obtain BEFORE authoring
|
|
91
91
|
|
|
92
|
-
When the settings line says `
|
|
92
|
+
When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
|
|
93
93
|
|
|
94
94
|
The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
95
95
|
|
|
@@ -103,9 +103,9 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
|
|
|
103
103
|
2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
|
|
104
104
|
3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
|
|
105
105
|
|
|
106
|
-
This is the rule the
|
|
106
|
+
This is the rule the curation hooks apply, so you read the index the Curate agent writes.
|
|
107
107
|
|
|
108
|
-
Before you author the workflow script, read `{ledger}/.devflow/
|
|
108
|
+
Before you author the workflow script, read `{ledger}/.devflow/curation/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
|
|
109
109
|
|
|
110
110
|
The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into the prompts of the Code, Fix, Design, Knowledge, Review and Harden agents, which follow `devflow:apply-decisions`. Those are the agent types above whose contract declares it; every other agent type gets no decisions context.
|
|
111
111
|
|
|
@@ -77,19 +77,19 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off>
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
90
90
|
### DECISIONS_CONTEXT — obtain BEFORE authoring
|
|
91
91
|
|
|
92
|
-
When the settings line says `
|
|
92
|
+
When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
|
|
93
93
|
|
|
94
94
|
The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
95
95
|
|
|
@@ -103,9 +103,9 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
|
|
|
103
103
|
2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
|
|
104
104
|
3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
|
|
105
105
|
|
|
106
|
-
This is the rule the
|
|
106
|
+
This is the rule the curation hooks apply, so you read the index the Curate agent writes.
|
|
107
107
|
|
|
108
|
-
Before you author the workflow script, read `{ledger}/.devflow/
|
|
108
|
+
Before you author the workflow script, read `{ledger}/.devflow/curation/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
|
|
109
109
|
|
|
110
110
|
The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into the prompts of the Code, Fix, Design, Knowledge, Review and Harden agents, which follow `devflow:apply-decisions`. Those are the agent types above whose contract declares it; every other agent type gets no decisions context.
|
|
111
111
|
|
|
@@ -77,19 +77,19 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off>
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
90
90
|
### DECISIONS_CONTEXT — obtain BEFORE authoring
|
|
91
91
|
|
|
92
|
-
When the settings line says `
|
|
92
|
+
When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
|
|
93
93
|
|
|
94
94
|
The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
95
95
|
|
|
@@ -103,9 +103,9 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
|
|
|
103
103
|
2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
|
|
104
104
|
3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
|
|
105
105
|
|
|
106
|
-
This is the rule the
|
|
106
|
+
This is the rule the curation hooks apply, so you read the index the Curate agent writes.
|
|
107
107
|
|
|
108
|
-
Before you author the workflow script, read `{ledger}/.devflow/
|
|
108
|
+
Before you author the workflow script, read `{ledger}/.devflow/curation/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
|
|
109
109
|
|
|
110
110
|
The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into the prompts of the Code, Fix, Design, Knowledge, Review and Harden agents, which follow `devflow:apply-decisions`. Those are the agent types above whose contract declares it; every other agent type gets no decisions context.
|
|
111
111
|
|
package/dist/commands/explore.md
CHANGED
|
@@ -32,19 +32,19 @@ $ARGUMENTS
|
|
|
32
32
|
|
|
33
33
|
**Produces:** DECISIONS_CONTEXT
|
|
34
34
|
|
|
35
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
35
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off>
|
|
41
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
42
42
|
|
|
43
43
|
The accepted line is the only source of these values.
|
|
44
44
|
|
|
45
45
|
### Load DECISIONS_CONTEXT
|
|
46
46
|
|
|
47
|
-
When the settings line says `
|
|
47
|
+
When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
|
|
48
48
|
|
|
49
49
|
The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
|
|
50
50
|
|
|
@@ -58,11 +58,11 @@ Line 1 is the checkout's toplevel, line 2 the common git directory. A git older
|
|
|
58
58
|
2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
|
|
59
59
|
3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
|
|
60
60
|
|
|
61
|
-
This is the rule the
|
|
61
|
+
This is the rule the curation hooks apply, so you read the index the Curate agent writes.
|
|
62
62
|
|
|
63
63
|
**Step 1 — Read the pre-rendered index:**
|
|
64
64
|
|
|
65
|
-
Attempt to read `{ledger}/.devflow/
|
|
65
|
+
Attempt to read `{ledger}/.devflow/curation/index.md`.
|
|
66
66
|
|
|
67
67
|
- If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
|
|
68
68
|
- If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
|
|
@@ -85,7 +85,7 @@ The orchestrator uses `DECISIONS_CONTEXT` locally when framing exploration — p
|
|
|
85
85
|
|
|
86
86
|
**Produces:** ORIENT_OUTPUT
|
|
87
87
|
|
|
88
|
-
Spawn `Agent(subagent_type="Skim")` with `
|
|
88
|
+
Spawn `Agent(subagent_type="Skim")` with `CURATION` from the settings line, to get codebase overview relevant to the exploration question:
|
|
89
89
|
|
|
90
90
|
- File structure and module boundaries in the target area
|
|
91
91
|
- Entry points and key abstractions
|