@nac3/forge-cli 0.2.0-alpha.59z.123 → 0.2.0-alpha.59z.158
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/dist/agents/bridge.d.ts +69 -0
- package/dist/agents/bridge.d.ts.map +1 -0
- package/dist/agents/bridge.js +295 -0
- package/dist/agents/bridge.js.map +1 -0
- package/dist/agents/cli_real.d.ts +38 -0
- package/dist/agents/cli_real.d.ts.map +1 -0
- package/dist/agents/cli_real.js +46 -0
- package/dist/agents/cli_real.js.map +1 -0
- package/dist/agents/config_schema.d.ts +1 -1
- package/dist/agents/config_schema.d.ts.map +1 -1
- package/dist/agents/config_schema.js +16 -0
- package/dist/agents/config_schema.js.map +1 -1
- package/dist/agents/defaults.d.ts.map +1 -1
- package/dist/agents/defaults.js.map +1 -1
- package/dist/agents/delegate.d.ts +36 -0
- package/dist/agents/delegate.d.ts.map +1 -0
- package/dist/agents/delegate.js +68 -0
- package/dist/agents/delegate.js.map +1 -0
- package/dist/agents/iterative_step.d.ts +95 -0
- package/dist/agents/iterative_step.d.ts.map +1 -0
- package/dist/agents/iterative_step.js +249 -0
- package/dist/agents/iterative_step.js.map +1 -0
- package/dist/agents/llm_step.d.ts +50 -0
- package/dist/agents/llm_step.d.ts.map +1 -0
- package/dist/agents/llm_step.js +28 -0
- package/dist/agents/llm_step.js.map +1 -0
- package/dist/agents/real_step_factory.d.ts +95 -0
- package/dist/agents/real_step_factory.d.ts.map +1 -0
- package/dist/agents/real_step_factory.js +51 -0
- package/dist/agents/real_step_factory.js.map +1 -0
- package/dist/agents/runner.d.ts +14 -0
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +10 -1
- package/dist/agents/runner.js.map +1 -1
- package/dist/agents/runtime.d.ts +115 -0
- package/dist/agents/runtime.d.ts.map +1 -0
- package/dist/agents/runtime.js +429 -0
- package/dist/agents/runtime.js.map +1 -0
- package/dist/agents/system_prompt.d.ts +36 -0
- package/dist/agents/system_prompt.d.ts.map +1 -0
- package/dist/agents/system_prompt.js +101 -0
- package/dist/agents/system_prompt.js.map +1 -0
- package/dist/agents/types.d.ts +12 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/types.js.map +1 -1
- package/dist/bin/yf.d.ts.map +1 -1
- package/dist/bin/yf.js +9 -0
- package/dist/bin/yf.js.map +1 -1
- package/dist/chat/claude_cli.d.ts +42 -0
- package/dist/chat/claude_cli.d.ts.map +1 -0
- package/dist/chat/claude_cli.js +299 -0
- package/dist/chat/claude_cli.js.map +1 -0
- package/dist/chat/graph_snapshot.d.ts +38 -0
- package/dist/chat/graph_snapshot.d.ts.map +1 -0
- package/dist/chat/graph_snapshot.js +159 -0
- package/dist/chat/graph_snapshot.js.map +1 -0
- package/dist/chat/ingest_session.d.ts +24 -4
- package/dist/chat/ingest_session.d.ts.map +1 -1
- package/dist/chat/ingest_session.js +139 -4
- package/dist/chat/ingest_session.js.map +1 -1
- package/dist/chat/panel.d.ts.map +1 -1
- package/dist/chat/panel.js +1358 -0
- package/dist/chat/panel.js.map +1 -1
- package/dist/chat/server.d.ts +21 -0
- package/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +904 -4
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/nac3_invoke.d.ts +5 -0
- package/dist/chat/tools/nac3_invoke.d.ts.map +1 -1
- package/dist/chat/tools/nac3_invoke.js +1 -0
- package/dist/chat/tools/nac3_invoke.js.map +1 -1
- package/dist/chat/tools.d.ts.map +1 -1
- package/dist/chat/tools.js +12 -0
- package/dist/chat/tools.js.map +1 -1
- package/dist/commands/agent.d.ts +12 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +92 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/chat.d.ts +10 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +12 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/director.d.ts +37 -0
- package/dist/commands/director.d.ts.map +1 -0
- package/dist/commands/director.js +290 -0
- package/dist/commands/director.js.map +1 -0
- package/dist/core/pilot_setup.d.ts +14 -1
- package/dist/core/pilot_setup.d.ts.map +1 -1
- package/dist/core/pilot_setup.js +62 -1
- package/dist/core/pilot_setup.js.map +1 -1
- package/dist/design/yujin_design_resolver.d.ts +77 -0
- package/dist/design/yujin_design_resolver.d.ts.map +1 -0
- package/dist/design/yujin_design_resolver.js +113 -0
- package/dist/design/yujin_design_resolver.js.map +1 -0
- package/dist/docs/doctrine/default-design-system.md +120 -0
- package/dist/docs/doctrine/language-sovereignty.md +143 -0
- package/dist/docs/doctrine/testing-policy.md +211 -0
- package/dist/nac3/approval_queue.d.ts +8 -0
- package/dist/nac3/approval_queue.d.ts.map +1 -1
- package/dist/nac3/approval_queue.js.map +1 -1
- package/dist/nac3/internal_manifest.d.ts.map +1 -1
- package/dist/nac3/internal_manifest.js +178 -0
- package/dist/nac3/internal_manifest.js.map +1 -1
- package/dist/office/excel.d.ts +22 -0
- package/dist/office/excel.d.ts.map +1 -1
- package/dist/office/excel.js +82 -0
- package/dist/office/excel.js.map +1 -1
- package/dist/qa/brain_matrix/fixtures/scenario_a11y_focus_after_open.json +22 -0
- package/dist/qa/brain_matrix/fixtures/scenario_a11y_label_unlabeled_button.json +26 -0
- package/dist/qa/brain_matrix/fixtures/scenario_agent_director_consults_workflow_before_dispatch.json +42 -0
- package/dist/qa/brain_matrix/fixtures/scenario_analyst_extracts_then_returns.json +28 -0
- package/dist/qa/brain_matrix/fixtures/scenario_coder_consults_nac_spec_before_writing.json +28 -0
- package/dist/qa/brain_matrix/fixtures/scenario_default_design_system_override_shadcn.json +45 -0
- package/dist/qa/brain_matrix/fixtures/scenario_default_design_system_use_card_template.json +44 -0
- package/dist/qa/brain_matrix/fixtures/scenario_director_delegates_to_analyst.json +26 -0
- package/dist/qa/brain_matrix/fixtures/scenario_director_no_self_delegation.json +20 -0
- package/dist/qa/brain_matrix/fixtures/scenario_director_terminal_done_marker.json +19 -0
- package/dist/qa/brain_matrix/fixtures/scenario_doctrine_discover_default_design_system.json +50 -0
- package/dist/qa/brain_matrix/fixtures/scenario_doctrine_discover_language_sovereignty.json +53 -0
- package/dist/qa/brain_matrix/fixtures/scenario_doctrine_discover_testing_policy.json +55 -0
- package/dist/qa/brain_matrix/fixtures/scenario_language_sovereignty_not_conducive_spa_python.json +61 -0
- package/dist/qa/brain_matrix/fixtures/scenario_language_sovereignty_user_picks_python.json +48 -0
- package/dist/qa/brain_matrix/fixtures/scenario_mcp_invoke_destructive_pauses_for_r8.json +42 -0
- package/dist/qa/brain_matrix/fixtures/scenario_mcp_invoke_happy_path_writes_pizarron.json +76 -0
- package/dist/qa/brain_matrix/fixtures/scenario_mcp_invoke_network_timeout_graceful.json +41 -0
- package/dist/qa/brain_matrix/fixtures/scenario_no_hardcoded_color_use_token.json +47 -0
- package/dist/qa/brain_matrix/fixtures/scenario_office_excel_update_cell_picks_right_verb.json +26 -0
- package/dist/qa/brain_matrix/fixtures/scenario_scaffolder_destructive_pauses_for_approval.json +23 -0
- package/dist/qa/brain_matrix/fixtures/scenario_sumie_icon_pick_from_catalog.json +56 -0
- package/dist/qa/brain_matrix/fixtures/scenario_tester_uses_shell_exec_only.json +27 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workflow/graph.d.ts +59 -0
- package/dist/workflow/graph.d.ts.map +1 -0
- package/dist/workflow/graph.js +137 -0
- package/dist/workflow/graph.js.map +1 -0
- package/dist/workflow/state.d.ts +34 -0
- package/dist/workflow/state.d.ts.map +1 -1
- package/dist/workflow/state.js.map +1 -1
- package/docs/doctrine/default-design-system.md +120 -0
- package/docs/doctrine/language-sovereignty.md +143 -0
- package/docs/doctrine/testing-policy.md +211 -0
- package/package.json +102 -100
- package/src/i18n/catalogs/ar.json +20 -1
- package/src/i18n/catalogs/de.json +20 -1
- package/src/i18n/catalogs/en.json +20 -21
- package/src/i18n/catalogs/es.json +20 -21
- package/src/i18n/catalogs/fr.json +20 -1
- package/src/i18n/catalogs/hi.json +20 -1
- package/src/i18n/catalogs/it.json +20 -1
- package/src/i18n/catalogs/ja.json +20 -1
- package/src/i18n/catalogs/pt.json +20 -1
- package/src/i18n/catalogs/zh.json +20 -1
- package/templates/sumi-context.template.md +57 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Default design system -- Yujin DS first
|
|
2
|
+
|
|
3
|
+
Fetch when the user discusses UI / component design / look-and-
|
|
4
|
+
feel (signals: "componente", "modal", "sidebar", "card", "view",
|
|
5
|
+
"icon", "color", "fuente", "diseno", "interfaz", "UI", "form",
|
|
6
|
+
"button", "table", "kanban", "tabs"). Auto-injected on every
|
|
7
|
+
turn whose intent matches the UI heuristic.
|
|
8
|
+
|
|
9
|
+
## Rule (single source of truth)
|
|
10
|
+
|
|
11
|
+
The default front-end design system for any Forge-generated
|
|
12
|
+
project is **Yujin Design System** (`yujin-design-system/`). The
|
|
13
|
+
package ships with 258 DTCG-compliant tokens, 30 NAC3-attributed
|
|
14
|
+
component templates, 170 sumi-e icons + a kanji wordmark
|
|
15
|
+
catalog, and font references (Google Fonts CDN, no bundled
|
|
16
|
+
binaries).
|
|
17
|
+
|
|
18
|
+
When the user asks for a UI element, agents MUST:
|
|
19
|
+
|
|
20
|
+
1. Consult `yujin.design.list-templates` to see which Yujin
|
|
21
|
+
components cover the kind of element being requested.
|
|
22
|
+
2. Use `yujin.design.get-template({slug})` to retrieve the HTML
|
|
23
|
+
+ CSS + `nac3_attrs` + variants for the picked component.
|
|
24
|
+
3. Splice the template into the project; do NOT hand-roll an
|
|
25
|
+
equivalent layout from scratch.
|
|
26
|
+
4. Iconography: only pick from `yujin.design.list-sumie` (170
|
|
27
|
+
canonical icons). Use `yujin.design.get-icon({slug})` to
|
|
28
|
+
inline the SVG. Do NOT generate or import third-party icons
|
|
29
|
+
(no Material, no Font Awesome) unless the user explicitly
|
|
30
|
+
asks (override flow below).
|
|
31
|
+
5. Colors / typography / spacing: only via tokens from
|
|
32
|
+
`yujin.design.tokens()`. Do NOT hardcode `#3A4DBC` or
|
|
33
|
+
`font-family: Inter`; use `var(--color-accent)` and
|
|
34
|
+
`var(--font-family-sans)`.
|
|
35
|
+
|
|
36
|
+
## Override flow
|
|
37
|
+
|
|
38
|
+
The user CAN override the default ("usa shadcn", "use Material",
|
|
39
|
+
"this app needs Tailwind only", "I want my own brand colors"):
|
|
40
|
+
|
|
41
|
+
- Agent invokes `yujin.design.override({system_id, reason})`.
|
|
42
|
+
- This is `policy: 'approval_required'` so R8 opens a modal.
|
|
43
|
+
- The user confirms (or rejects); the choice persists in
|
|
44
|
+
`tenant_config.design_override`.
|
|
45
|
+
- Subsequent turns honor the override + the doctrine becomes a
|
|
46
|
+
soft suggestion ("Yujin DS is the Forge default, but this
|
|
47
|
+
tenant has overridden to <system>").
|
|
48
|
+
|
|
49
|
+
## Why this is the default
|
|
50
|
+
|
|
51
|
+
- Coherent visual language across every Forge-generated product
|
|
52
|
+
-- the user does not need to re-learn the look-and-feel per
|
|
53
|
+
product.
|
|
54
|
+
- 30 components are enough to compose every standard SaaS UX
|
|
55
|
+
(CRM, admin panel, marketing site, e-commerce, dashboard,
|
|
56
|
+
task tracker, settings).
|
|
57
|
+
- NAC3 attributes pre-applied -- every Yujin component is
|
|
58
|
+
voice-controllable + accessibility-ready out of the box.
|
|
59
|
+
- 170 sumi-e icons cover virtually every business concept
|
|
60
|
+
(finance, sales, support, manufacturing, quality, HR, mobile,
|
|
61
|
+
AI, comms, document, geo, weather, animal). One coherent
|
|
62
|
+
illustration style.
|
|
63
|
+
|
|
64
|
+
## Files in the package
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
yujin-design-system/
|
|
68
|
+
manifest.json catalog + version + license
|
|
69
|
+
tokens/
|
|
70
|
+
yujin-tokens.json 258 DTCG W3C tokens
|
|
71
|
+
yujin-tokens.css generated CSS (same source-of-truth)
|
|
72
|
+
components/
|
|
73
|
+
_index.json list of 30 components by category
|
|
74
|
+
button.yujin.json one file per component
|
|
75
|
+
card.yujin.json
|
|
76
|
+
... (30 total)
|
|
77
|
+
icons/
|
|
78
|
+
sumie/
|
|
79
|
+
manifest.json 170 icons with tags
|
|
80
|
+
branch-sakura.svg one SVG file per icon
|
|
81
|
+
... (170 total)
|
|
82
|
+
fonts/
|
|
83
|
+
README.md reference-only policy (Google Fonts CDN)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Six NAC3 verbs
|
|
87
|
+
|
|
88
|
+
| Verb | Returns | Policy |
|
|
89
|
+
|---------------------------------|----------------------------------------------------|--------------------|
|
|
90
|
+
| `yujin.design.list-templates` | `[{slug, category, description, variants}]` | safe |
|
|
91
|
+
| `yujin.design.get-template` | full ComponentTemplate (html, css, nac3, props) | safe |
|
|
92
|
+
| `yujin.design.list-sumie` | `[{slug, tags, file}]` (filtered by tag if given) | safe |
|
|
93
|
+
| `yujin.design.get-icon` | inline SVG string | safe |
|
|
94
|
+
| `yujin.design.tokens` | full DTCG token tree | safe |
|
|
95
|
+
| `yujin.design.override` | persists tenant_config.design_override | approval-required |
|
|
96
|
+
|
|
97
|
+
## What this doctrine does NOT cover
|
|
98
|
+
|
|
99
|
+
- Framework choice within TypeScript (Vue vs React vs Svelte).
|
|
100
|
+
See `docs/doctrine/language-sovereignty.md` -- the user
|
|
101
|
+
decides per slot, and the doctrine table records the choice.
|
|
102
|
+
- Build tooling (Vite vs Webpack vs esbuild). Out of scope.
|
|
103
|
+
- Theme switching per tenant. The override flow above persists
|
|
104
|
+
one choice per tenant; multi-theme support is a separate
|
|
105
|
+
feature.
|
|
106
|
+
|
|
107
|
+
## What the WORKERS (Analyst, Coder, Director) do with this
|
|
108
|
+
|
|
109
|
+
- **Analyst**: when extracting a spec that mentions UI elements
|
|
110
|
+
(forms, dashboards, modals), tag each one with the matching
|
|
111
|
+
Yujin component slug in `plan.components[]`. The Coder then
|
|
112
|
+
knows which template to pull.
|
|
113
|
+
- **Coder**: before writing ANY UI file, invoke
|
|
114
|
+
`yujin.design.list-templates` + `yujin.design.get-template`
|
|
115
|
+
for the components in the plan. Splice the templates. Apply
|
|
116
|
+
variants from the spec. Do NOT hand-write `.css` from
|
|
117
|
+
scratch.
|
|
118
|
+
- **Director**: when the user explicitly requests an override
|
|
119
|
+
("use shadcn"), invokes `yujin.design.override` instead of
|
|
120
|
+
silently accepting. The R8 modal confirms.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Language sovereignty -- the user picks, the Director suggests
|
|
2
|
+
|
|
3
|
+
Fetch when the user discusses programming language choice in
|
|
4
|
+
architecture / RFP / Arch / Design phases (workflow phases II
|
|
5
|
+
and III), OR when an Analyst extracts a spec that mentions a
|
|
6
|
+
language explicitly (signals: "in node", "with django", "react
|
|
7
|
+
native", "pure rust", "java backend", "swift app").
|
|
8
|
+
|
|
9
|
+
## Rule (single source of truth)
|
|
10
|
+
|
|
11
|
+
The user picks the programming language for each component. The
|
|
12
|
+
Director SUGGESTS during architecture (phase III specs / RFP)
|
|
13
|
+
but NEVER imposes. If the user insists on a language different
|
|
14
|
+
from the one the Director suggested, the Director performs a
|
|
15
|
+
SWITCH and persists the choice in `workflow.language_choices`
|
|
16
|
+
via `yujin.workflow.set`.
|
|
17
|
+
|
|
18
|
+
The ONLY exception is when the language the user requested is
|
|
19
|
+
not conducive to the component being developed (technical
|
|
20
|
+
incompatibility documentable from the table below). In that
|
|
21
|
+
case the Director replies with the exact row from this doctrine
|
|
22
|
+
+ the valid alternatives + waits for the next user decision. No
|
|
23
|
+
"I deny because I dislike", only "I deny because <component-kind>
|
|
24
|
+
cannot run on <language> because <technical reason>".
|
|
25
|
+
|
|
26
|
+
## Suitability table
|
|
27
|
+
|
|
28
|
+
The table is the single source of truth. The Director MUST read
|
|
29
|
+
from it and MUST NOT add opinions on top.
|
|
30
|
+
|
|
31
|
+
| Component kind | Conducive languages | NOT conducive (with reason) |
|
|
32
|
+
|-------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
|
|
33
|
+
| spa-web-frontend | ts, js, wasm-target (rust, go, c#), htmx-fragments | python, java, php, ruby (server-side runtimes, not a browser runtime) |
|
|
34
|
+
| mobile-native | swift (ios), kotlin (android), dart (flutter), ts+rn (expo) | python, php, c# (no fluid native mobile runtime); html-only (not native) |
|
|
35
|
+
| mobile-cross-platform | dart (flutter), ts+rn (expo), kotlin-multiplatform | jvm-only languages (not a mobile target), php, perl |
|
|
36
|
+
| backend-api | ts, js, python, go, rust, java, kotlin, c#, php, ruby, elixir | bash, asm (do not scale to productive HTTP servers); assembler (no http stack) |
|
|
37
|
+
| backend-realtime | go, rust, elixir, ts (node), kotlin, c# (signalr) | python (gil bottleneck for sustained ws), php (request-response model) |
|
|
38
|
+
| kernel-driver | c, rust, asm | ts, python, java, c# (managed runtimes do not touch metal) |
|
|
39
|
+
| embedded-firmware | c, rust, c++, micropython (mid-range), zig | java, ts, php (heavyweight runtimes for typical mcus) |
|
|
40
|
+
| data-pipeline | python, scala, java, go, sql, kotlin | js (poor batch ecosystem), php (no parallel data tooling) |
|
|
41
|
+
| ml-training | python, julia, r, c++ (kernels) | ts, php, ruby (no mature ml ecosystem comparable) |
|
|
42
|
+
| ml-inference | python, ts, c++, rust, go (onnx) | php, perl (no inference runtime) |
|
|
43
|
+
| db-stored-proc | sql, pl/pgsql, t-sql, pl/sql (oracle) | any general-purpose language (not the db engine model) |
|
|
44
|
+
| db-migration | sql + migration runner (any: rails, alembic, prisma, flyway) | -- |
|
|
45
|
+
| cli-tool | go, rust, ts (node), python, c (oneshot) | -- (almost any general-purpose lang works) |
|
|
46
|
+
| static-analysis-plugin | language of the target compiler | any unrelated language (no compiler integration point) |
|
|
47
|
+
| infra-as-code | terraform/hcl, pulumi (ts/python/go), cloudformation/yaml, cdk | bash one-offs (do not represent desired state) |
|
|
48
|
+
| iot-edge | rust, c, go, python (rpi-class), elixir (nerves) | jvm-only (mostly too heavy), php |
|
|
49
|
+
| build-system | go, rust, ts (node), make, bash | -- (almost any works; nuance is in ergonomics, not correctness) |
|
|
50
|
+
| docs-site | markdown + static site gen (any), mdx (react) | dynamic backends (overkill; not conducive to content-as-code) |
|
|
51
|
+
|
|
52
|
+
## Algorithm (Director executes this)
|
|
53
|
+
|
|
54
|
+
1. User input: "quiero X en LANG".
|
|
55
|
+
2. Director: `yujin.doctrine.discover({slugs:["language-sovereignty"]})`.
|
|
56
|
+
3. Director: lookup the row for `X` (component-kind). If
|
|
57
|
+
ambiguous, ASK the user one clarifying question (which kind
|
|
58
|
+
of component is X?) before proceeding. Do NOT guess.
|
|
59
|
+
4. If `LANG` is in `row.conducive`:
|
|
60
|
+
- switch: set `workflow.language_choices[X] = { lang: LANG,
|
|
61
|
+
decided_at: NOW, decided_by: "user" }` via
|
|
62
|
+
`yujin.workflow.set`.
|
|
63
|
+
- Reply briefly: "Listo, X en LANG. Sigo con el plan."
|
|
64
|
+
- Do NOT discuss the choice further unless the user asks.
|
|
65
|
+
5. If `LANG` is NOT in `row.conducive`:
|
|
66
|
+
- Reply with the exact row from this doctrine:
|
|
67
|
+
"LANG no es conducente para X porque <row.NOT_conducive_reason>.
|
|
68
|
+
Las opciones validas son: <row.conducive>. Cual preferis?"
|
|
69
|
+
- Do NOT switch. Wait for the next user decision.
|
|
70
|
+
6. If the user counter-argues with NEW technical information
|
|
71
|
+
("hay un transpiler de LANG a JS / WASM target / etc"):
|
|
72
|
+
- Director re-evaluates. If the new info is verifiable +
|
|
73
|
+
consistent with the table semantics (e.g. WASM target for
|
|
74
|
+
the kind), update the conducive set in memory for THIS
|
|
75
|
+
turn + switch.
|
|
76
|
+
- If the info is opinable / not verifiable, hold the negative
|
|
77
|
+
+ explain the gap (mismatched runtime model, no compiler
|
|
78
|
+
integration, etc).
|
|
79
|
+
|
|
80
|
+
## Defaults when the user has NOT expressed preference
|
|
81
|
+
|
|
82
|
+
When the user has not yet declared a language for a component
|
|
83
|
+
slot, the Director may suggest a default. Defaults are NOT
|
|
84
|
+
prescriptions; they exist so the conversation can move forward
|
|
85
|
+
without a 12-question survey.
|
|
86
|
+
|
|
87
|
+
| Slot | Default suggestion |
|
|
88
|
+
|---------------------|------------------------------|
|
|
89
|
+
| frontend | ts (react / typescript) |
|
|
90
|
+
| mobile | ts (react native + expo) |
|
|
91
|
+
| backend | ts (node) for crud-heavy; go for perf-sensitive; python for ml-heavy |
|
|
92
|
+
| data-pipeline | python |
|
|
93
|
+
| infra | terraform + hcl |
|
|
94
|
+
| db | postgres + sql migrations |
|
|
95
|
+
| ml | python |
|
|
96
|
+
|
|
97
|
+
The Director surfaces the default as a SUGGESTION ("propongo TS
|
|
98
|
+
para frontend y Python para el pipeline; te sirve?") and
|
|
99
|
+
proceeds if the user accepts or stays silent on it (silence is
|
|
100
|
+
acceptance of the default). The persisted `decided_by` field
|
|
101
|
+
records `"director_suggested"` so a future audit can distinguish
|
|
102
|
+
explicit choices from accepted defaults.
|
|
103
|
+
|
|
104
|
+
## Where the decision lives
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
yujin.forge.json -> workflow.language_choices: {
|
|
108
|
+
frontend: { lang: "ts", decided_at: "...", decided_by: "user" },
|
|
109
|
+
backend: { lang: "go", decided_at: "...", decided_by: "user" },
|
|
110
|
+
mobile: { lang: "dart", decided_at: "...", decided_by: "director_suggested" },
|
|
111
|
+
data_pipeline: { lang: "python", decided_at: "...", decided_by: "user" },
|
|
112
|
+
infra: { lang: "tf+hcl", decided_at: "...", decided_by: "director_suggested" }
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Read via `yujin.workflow.state`. Write via `yujin.workflow.set
|
|
117
|
+
{path: "language_choices.<slot>", value: {...}}`.
|
|
118
|
+
|
|
119
|
+
## What this doctrine does NOT cover
|
|
120
|
+
|
|
121
|
+
- Frameworks within a language (vue vs react vs svelte for ts
|
|
122
|
+
frontend). That is a separate user decision the Director
|
|
123
|
+
surfaces but does not constrain via this doctrine.
|
|
124
|
+
- Library choices (express vs fastify vs hono for ts backend).
|
|
125
|
+
Same: user decides.
|
|
126
|
+
- Build tooling (vite vs webpack vs esbuild). Same.
|
|
127
|
+
|
|
128
|
+
## What the WORKERS (Analyst, Coder, Tester, Scaffolder) read from this doctrine
|
|
129
|
+
|
|
130
|
+
- **Analyst**: when extracting a spec, capture explicit language
|
|
131
|
+
signals into `plan.language_signals[]`. The Director processes
|
|
132
|
+
them via the algorithm above.
|
|
133
|
+
- **Coder**: read `workflow.language_choices` before proposing
|
|
134
|
+
files. Match the chosen language; do NOT default to TS if the
|
|
135
|
+
table chose Go.
|
|
136
|
+
- **Tester**: detect the test framework FROM the chosen language
|
|
137
|
+
+ project manifest (`package.json` -> Vitest/Jest, `pyproject.toml`
|
|
138
|
+
-> pytest, `go.mod` -> go test, `Cargo.toml` -> cargo test,
|
|
139
|
+
`composer.json` -> PHPUnit). Do NOT prompt the user for the
|
|
140
|
+
framework when the manifest already says.
|
|
141
|
+
- **Scaffolder**: respect file extensions + import statements of
|
|
142
|
+
the chosen language stack. Do not write `.ts` files into a Go
|
|
143
|
+
module.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Testing policy (Forge product principle)
|
|
2
|
+
|
|
3
|
+
**Lock date:** 2026-06-04. Replaces the earlier draft
|
|
4
|
+
`tdd-first.md` which proposed TDD-first universally.
|
|
5
|
+
|
|
6
|
+
Pablo's review: TDD-first as a universal product principle has
|
|
7
|
+
more downsides than upsides. The cost is real (tokens, latency,
|
|
8
|
+
arquitectural lock-in, frustrated UX, ambiguous specs) and only
|
|
9
|
+
pays off in a narrow slice (backends + middleware + finance +
|
|
10
|
+
regulatory + external integrations). For the majority of Forge
|
|
11
|
+
projects (UI / dashboards / CRUDs / demos / glue), TDD-first
|
|
12
|
+
slows down iteration without adding value.
|
|
13
|
+
|
|
14
|
+
This doctrine sets the new rule.
|
|
15
|
+
|
|
16
|
+
## The rule
|
|
17
|
+
|
|
18
|
+
1. **Tests are required POST-implementation for every change**
|
|
19
|
+
that lands in a Forge-managed project. The default order is:
|
|
20
|
+
spec -> code -> tests -> scaffold-with-gate.
|
|
21
|
+
2. **TDD-first is opt-in**, not default. It applies when the
|
|
22
|
+
slice falls into the **TDD-first scope** (see below).
|
|
23
|
+
3. **The scaffold gate** requires the test suite to be green
|
|
24
|
+
before writing to disk, regardless of order. The order
|
|
25
|
+
determines WHEN tests are authored, not whether they exist.
|
|
26
|
+
|
|
27
|
+
## TDD-first scope (the narrow slice)
|
|
28
|
+
|
|
29
|
+
Only these domains warrant test-first:
|
|
30
|
+
|
|
31
|
+
- **APIs / backend endpoints with public contract**. The
|
|
32
|
+
request/response shape is the most stable thing about the
|
|
33
|
+
feature; the implementation will rewrite.
|
|
34
|
+
- **Data transformers / validators / parsers** where input
|
|
35
|
+
-> output is the whole point.
|
|
36
|
+
- **Financial / regulatory / mathematical logic** (tax calc,
|
|
37
|
+
retention, currency conversion, legal rules). The test
|
|
38
|
+
is the spec.
|
|
39
|
+
- **External-service integrations** (Stripe webhook, Polar,
|
|
40
|
+
OAuth, NAC bridges to MCP). Tests capture "this payload
|
|
41
|
+
produces this effect" which is the only stable contract
|
|
42
|
+
when the provider changes internals.
|
|
43
|
+
|
|
44
|
+
The Analyst marks the spec extraction with `tdd_first: true`
|
|
45
|
+
when:
|
|
46
|
+
|
|
47
|
+
- The plan contains `endpoints` AND no `components`.
|
|
48
|
+
- OR any extraction tag matches /financial|tax|regulatory|
|
|
49
|
+
integration|webhook|validator|transformer/i.
|
|
50
|
+
- OR the user explicitly passes `--tdd` to `yf spec extract`.
|
|
51
|
+
|
|
52
|
+
When `tdd_first: false` (default), the Tester slot runs AFTER
|
|
53
|
+
the Coder. When true, the Tester slot runs BEFORE the Coder.
|
|
54
|
+
|
|
55
|
+
## TDD-first explicitly NOT for
|
|
56
|
+
|
|
57
|
+
- UI / frontend / drag-drop / animations / layout.
|
|
58
|
+
- Glue code / scripts / one-off transforms.
|
|
59
|
+
- Demos / prototypes / spikes (always `--mode=spike`).
|
|
60
|
+
- Stateful interactive surfaces (games, audio, sensor).
|
|
61
|
+
- Generated code from templates (Next.js scaffolds, etc.) --
|
|
62
|
+
the template has its own tests; user-added features follow
|
|
63
|
+
the default order.
|
|
64
|
+
|
|
65
|
+
Trying to TDD any of the above is fiction-writing. The tests
|
|
66
|
+
end up tautological (matching implementation) or vacuous
|
|
67
|
+
(asserting things that are trivially true). Forge will not
|
|
68
|
+
force users into that.
|
|
69
|
+
|
|
70
|
+
## Order of the 5 Director agents (canonical)
|
|
71
|
+
|
|
72
|
+
The Tester is NOT a single-shot slot -- it is re-entrant. It
|
|
73
|
+
runs at every checkpoint where the suite needs to be authored
|
|
74
|
+
or verified. In TDD-first, that's twice. In code-first, that's
|
|
75
|
+
once. The diagram below names the runs explicitly.
|
|
76
|
+
|
|
77
|
+
### TDD-first mode (Analyst tags `tdd_first: true`)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
Director (orchestrator)
|
|
81
|
+
|
|
|
82
|
+
v
|
|
83
|
+
Analyst -- extract spec + tag tdd_first=true
|
|
84
|
+
|
|
|
85
|
+
v
|
|
86
|
+
Tester #1 -- write the test suite (RED). Suite fails because
|
|
87
|
+
no code exists yet.
|
|
88
|
+
|
|
|
89
|
+
v
|
|
90
|
+
Coder -- implement until the suite turns green. Iterates
|
|
91
|
+
with the brain until red->green or max iter cap.
|
|
92
|
+
|
|
|
93
|
+
v
|
|
94
|
+
Tester #2 -- verify green + add edge-case pass (3 boundary
|
|
95
|
+
tests). If any test still red after edge pass,
|
|
96
|
+
back to Coder (capped by max iter).
|
|
97
|
+
|
|
|
98
|
+
v
|
|
99
|
+
Scaffolder -- apply to disk ONLY when Tester #2 reports
|
|
100
|
+
all-green (happy + edge cases).
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Code-first mode (Analyst tags `tdd_first: false`, the default)
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Director (orchestrator)
|
|
107
|
+
|
|
|
108
|
+
v
|
|
109
|
+
Analyst -- extract spec + tag tdd_first=false
|
|
110
|
+
|
|
|
111
|
+
v
|
|
112
|
+
Coder -- implement straight from the plan.
|
|
113
|
+
|
|
|
114
|
+
v
|
|
115
|
+
Tester -- write the test suite POST-implementation +
|
|
116
|
+
verify green + edge-case pass.
|
|
117
|
+
|
|
|
118
|
+
v
|
|
119
|
+
Scaffolder -- apply to disk ONLY when Tester reports
|
|
120
|
+
all-green.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
In both modes, the **last Tester pass before Scaffolder is the
|
|
124
|
+
hard gate**. The flag `tdd_first` decides whether there is also
|
|
125
|
+
a FIRST Tester pass that writes red. The Scaffolder gate
|
|
126
|
+
(green-required) is identical in both modes.
|
|
127
|
+
|
|
128
|
+
The bridge ACL stays the same regardless of mode:
|
|
129
|
+
`Director.can_call = [Analyst, Tester, Coder, Scaffolder]`
|
|
130
|
+
and each worker accepts only from Director. Mode is encoded
|
|
131
|
+
in the messages, not in the topology.
|
|
132
|
+
|
|
133
|
+
## The scaffold gate (regardless of order)
|
|
134
|
+
|
|
135
|
+
`Scaffolder` refuses to write to disk when:
|
|
136
|
+
|
|
137
|
+
- The Tester report does not exist for the slice.
|
|
138
|
+
- Any test in the new suite is red.
|
|
139
|
+
|
|
140
|
+
The gate is enforced in `src/chat/spec_scaffold.ts`. Test
|
|
141
|
+
runner auto-detected from `package.json` / `pyproject.toml` /
|
|
142
|
+
etc.
|
|
143
|
+
|
|
144
|
+
## Loop protection (when iterating to green)
|
|
145
|
+
|
|
146
|
+
If the Coder iterates more than `agent.director.max_iters_to_green`
|
|
147
|
+
times (default 5) without turning the test suite green, the
|
|
148
|
+
agent stops and reports the failure to the Director, which
|
|
149
|
+
opens an R8 modal with three options for the user:
|
|
150
|
+
|
|
151
|
+
1. Mark suite as accepted-red (the user knows the tests are
|
|
152
|
+
wrong; accept the implementation as-is). Audit-logged.
|
|
153
|
+
2. Re-extract spec (back to Analyst with clarification).
|
|
154
|
+
3. Cancel the slice.
|
|
155
|
+
|
|
156
|
+
This is the answer to "what does the agent do when it cannot
|
|
157
|
+
turn red into green". No silent application. No infinite
|
|
158
|
+
iteration.
|
|
159
|
+
|
|
160
|
+
## Mitigations against test pathologies
|
|
161
|
+
|
|
162
|
+
Even POST-implementation testing can produce bad suites if
|
|
163
|
+
left to the Tester LLM alone. Required mitigations:
|
|
164
|
+
|
|
165
|
+
- **Contract framing in Tester system prompt**: the prompt
|
|
166
|
+
explicitly says "tests assert CONTRACT (input -> output,
|
|
167
|
+
effect on world), NOT implementation. Internal refactors
|
|
168
|
+
should not break a well-written test."
|
|
169
|
+
- **Edge-case pass**: after the happy-path tests are green,
|
|
170
|
+
the Tester runs a second pass generating 3 edge cases
|
|
171
|
+
(nulls, empty, boundary, error). Adds them to the suite.
|
|
172
|
+
Coder iterates again.
|
|
173
|
+
- **No mocking-of-self**: tests cannot mock the function
|
|
174
|
+
they are testing. Mocking external deps (network, fs) is
|
|
175
|
+
allowed.
|
|
176
|
+
- **Tester report includes coverage line + branch %.**
|
|
177
|
+
Below configurable threshold (default 80% line, 70%
|
|
178
|
+
branch) is logged as a warning, not a block.
|
|
179
|
+
|
|
180
|
+
## What this doctrine covers + does NOT cover
|
|
181
|
+
|
|
182
|
+
This doctrine covers **functional correctness via tests**.
|
|
183
|
+
It does NOT cover:
|
|
184
|
+
|
|
185
|
+
- **UX quality** -- panel review, manual walkthroughs.
|
|
186
|
+
- **Accessibility** -- separate doctrine `accessibility.md`
|
|
187
|
+
+ `yujin.a11y.*` verbs.
|
|
188
|
+
- **Performance** -- separate (future doctrine, not blocking).
|
|
189
|
+
- **Security** -- separate.
|
|
190
|
+
- **Design / aesthetic** -- not testable by code.
|
|
191
|
+
|
|
192
|
+
"100% E2E tests passed" in the Director objective means
|
|
193
|
+
"functional contract passes". Other quality dimensions are
|
|
194
|
+
gated separately or via human review.
|
|
195
|
+
|
|
196
|
+
## How Sumi enforces this on Forge itself (dogfood)
|
|
197
|
+
|
|
198
|
+
Sumi-self ships every Forge slice with tests. The order
|
|
199
|
+
follows the same rule:
|
|
200
|
+
|
|
201
|
+
- Backend / middleware / integration slice -> TDD-first
|
|
202
|
+
(test then code). The bridge.ts slice was this kind, and
|
|
203
|
+
the bug found by the test is the evidence the order paid
|
|
204
|
+
off there.
|
|
205
|
+
- UI / panel / cosmetic slice -> code-first then test. The
|
|
206
|
+
legal modal opacity fix, the audit log preview, the
|
|
207
|
+
Limites alignment -- all of these were code-first because
|
|
208
|
+
the shape was visual and exploratory.
|
|
209
|
+
|
|
210
|
+
Sumi decides the order per slice. The graph rule #12 reflects
|
|
211
|
+
this.
|