create-flowdular 0.6.1 → 0.6.3

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.
Files changed (35) hide show
  1. package/agent-template/.agents/skills/module-new/SKILL.md +1 -1
  2. package/agent-template/.agents/skills/module-update/SKILL.md +1 -1
  3. package/agent-template/.agents/skills/perf-audit/SKILL.md +1 -1
  4. package/agent-template/.ai/agents/README.md +2 -2
  5. package/agent-template/.ai/agents/sandbox/agentic-engineer.md +1 -1
  6. package/agent-template/.ai/agents/sandbox/backend-engineer.md +1 -1
  7. package/agent-template/.ai/agents/sandbox/business-manager.md +1 -3
  8. package/agent-template/.ai/agents/sandbox/frontend-engineer.md +1 -1
  9. package/agent-template/.ai/agents/sandbox/ux-designer.md +1 -1
  10. package/agent-template/.ai/policies/model-routing.yaml +2 -1
  11. package/agent-template/.ai/policies/task-budgets.yaml +1 -1
  12. package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.up.sql +2 -2
  13. package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.up.sql +2 -2
  14. package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +2 -2
  15. package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +2 -2
  16. package/agent-template/.ai/references/catalog/module.json +3 -3
  17. package/agent-template/.ai/references/catalog/package.json +2 -2
  18. package/agent-template/.ai/references/catalog/spec/module.yaml +3 -3
  19. package/agent-template/.ai/references/catalog/src/client/CatalogItemForm.tsrx +2 -2
  20. package/agent-template/.ai/references/catalog/src/services/migration.ts +8 -8
  21. package/agent-template/.ai/references/catalog/tests/migrations.test.ts +1 -1
  22. package/agent-template/.ai/skills/module-new/SKILL.md +1 -1
  23. package/agent-template/.ai/skills/module-update/SKILL.md +1 -1
  24. package/agent-template/.ai/skills/perf-audit/SKILL.md +1 -1
  25. package/agent-template/.claude/skills/module-new/SKILL.md +1 -1
  26. package/agent-template/.claude/skills/module-update/SKILL.md +1 -1
  27. package/agent-template/.claude/skills/perf-audit/SKILL.md +1 -1
  28. package/agent-template/docs/module-distribution.md +1 -2
  29. package/agent-template/docs/modules.md +2 -2
  30. package/agent-template/docs/sandbox.md +41 -3
  31. package/package.json +1 -1
  32. package/template/default/modules/example/package.json +1 -1
  33. package/template/default/package.json +2 -2
  34. package/template/default/platform/package.json +1 -1
  35. package/agent-template/.ai/references/catalog.provenance.json +0 -65
@@ -14,7 +14,7 @@ Two ways to land the same module: the sandbox (a brief, specialist turns, gates
14
14
 
15
15
  With an approved `schemaVersion: 2` spec, the specification is the requirement document and you do not go looking for one. Read the spec, the files on this skill's touch list, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`; `.ai/platform-capabilities.md` answers what the platform provides, and the reference module answers what the code looks like.
16
16
 
17
- Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is `HANDOFF: business-manager - <what is missing>`; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
17
+ Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is a `questions` block the operator answers, and the business manager records an answer that changes the spec for a new approval before you continue; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
18
18
 
19
19
  Every `acceptanceScenarios[]` entry maps to at least one test in `tests/`. A scenario with no test is unfinished work, and the scenario id belongs in the test name so the mapping is readable.
20
20
 
@@ -10,7 +10,7 @@ description: >-
10
10
 
11
11
  With an approved `schemaVersion: 2` spec delta, the specification is the requirement document. Read the spec, the module itself, the touch list for the change class below, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`: `.ai/platform-capabilities.md` answers what the platform provides.
12
12
 
13
- Anything the delta does not say is a spec defect, not your decision. Report it back (`HANDOFF: business-manager - <what is missing>` in the sandbox, a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
13
+ Anything the delta does not say is a spec defect, not your decision. Report it back (a `questions` block in the sandbox, which the business manager turns into a spec delta for a new approval when the answer changes the spec; a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
14
14
 
15
15
  The spec-element to file mapping is the table in `module-new`; the change classes below are the same mapping arranged by what you are changing.
16
16
 
@@ -93,6 +93,6 @@ Complexity to state in the review: for each new data structure and loop on a req
93
93
  ## Pitfalls
94
94
 
95
95
  - `LIKE` or `=` against `lower(column)` cannot use a plain `(tenant_id, column)` index; store a normalized column (`sku_normalized`) as `.ai/references/catalog` does, or add an expression index on `lower(column)`.
96
- - `ORDER BY lower(name)` (`Flowdular/official-modules`, `modules/parties`) cannot use the `(tenant_id, name, id)` index for the sort; acceptable at current sizes, name it if parties grow.
96
+ - `ORDER BY lower(name)` cannot use a `(tenant_id, name, id)` index for the sort; acceptable at small sizes, name it once the table grows.
97
97
  - A `Kpi` that shows `items.length` after loading the full list is O(rows) network per dashboard load.
98
98
  - Never change behaviour in a performance commit; keep the functional tests green and add none that assert internal call counts.
@@ -8,9 +8,9 @@ Two families of role prompts live here. They share one front matter schema (`id`
8
8
 
9
9
  What the front matter does at run time:
10
10
 
11
- - `gates`: enforced. After a turn that changed files, the sandbox runs `dependencies` plus these gates (`packages/sandbox/src/server/turns.ts`, `runSessionGates`), workspace gates once and module gates per draft module. Ids must come from `packages/sandbox/src/server/gates.ts`: `spec-schema`, `module-schema`, `dependencies`, `typecheck`, `tests`, `format`. An unknown id is dropped silently. The failing gate's command and output go into the fix prompt.
11
+ - `gates`: enforced. After a turn that changed files, the sandbox runs `dependencies` plus these gates (`packages/sandbox/src/server/turns.ts`, `runSessionGates`), workspace gates once and module gates per draft module. Ids must come from `packages/sandbox/src/server/gates.ts`: `spec-schema`, `module-schema`, `dependencies`, `typecheck`, `tests`, `format`. An unknown id is dropped silently. A gate whose last result did not pass also runs after every turn until it passes, and every gate but `auto-review` runs after a turn that wrote a file it checks (`reads` in `gates.ts`) once the module has its `module.json`. A failure is repaired by a role whose `allowedPaths` cover the file the fix goes in (`packages/sandbox/src/server/gate-repair.ts`), with the reported errors in the fix prompt.
12
12
  - `allowedPaths`: enforced after every turn. Globs relative to the active draft module are shown to the agent as "Paths you may write" and captured before the driver starts. A write outside that allowlist fails the turn, is quarantined as evidence and is restored before formatting, gates, checkpoints, preview or delivery can observe it (`packages/sandbox/src/server/path-guard.ts`, `turns.ts`).
13
- - `handoff`: enforced. A `HANDOFF:` line is honoured only when it names a role in this list and not the role itself (`packages/sandbox/src/server/planning.ts`); otherwise the state routing decides and the transcript says why. The team list in the instruction is built from this list.
13
+ - `handoff`: enforced. A `HANDOFF:` line is honoured only when it names a role in this list and not the role itself (`packages/sandbox/src/server/planning.ts`); otherwise the state routing decides and the transcript says why. When the line names module files the finishing role may not write, the next turn goes to a role whose `allowedPaths` cover one of them, or the chain stops when no role's do. The team list in the instruction is built from this list.
14
14
  - `id`, `name`, `purpose`: composed into the instruction after `SANDBOX_AGENT_CONTRACT`, before the session facts.
15
15
 
16
16
  The five roles and who takes the first turn: `business-manager` for both a new module and a change to an existing module. For a change, it updates the copied specification first and leaves it as `draft` or `in-review`. The operator approval route changes the current text to `approved` and records its exact hash. Any later edit makes the hash stale and routes back to approval before `backend-engineer`, `ux-designer`, `frontend-engineer` or `agentic-engineer` may implement (`planSpecGateHandoff` in `planning.ts`, `isSpecApproved` in `spec.ts`).
@@ -29,4 +29,4 @@ The allowed tool list is a maximum. Effective authority also requires tenant bin
29
29
 
30
30
  Module-owned agents require a tenant provider/model binding, retained definition revisions and an exact tool ceiling. Never pin provider credentials or use wildcard tools. Procedures stored by agents.core are business data, unrelated to coding skills.
31
31
 
32
- If the requested surface needs a missing endpoint/service, hand off to backend. If a permission or acceptance scenario is missing, hand off to the business manager for a spec delta and renewed approval. Never edit another module or platform package from this session.
32
+ If the requested surface needs a missing endpoint/service, hand off to backend. If a permission, tool or acceptance scenario the work needs is not in the approved spec, ask for it with a questions block (Session); never add it yourself. Never edit another module or platform package from this session.
@@ -43,4 +43,4 @@ Test observable behavior: successful operations, validation bounds, 401/403, uni
43
43
 
44
44
  Operator sample data comes from the sample-data tool or reference/sample-data.json. Derive tests/fixtures/\*.json and preview/seed.json from its shape with invented names, contacts and identifiers. src/preview.ts exports an idempotent seed({ tenantId, accountId, data, databases }) that writes through the module repository. A spec research section reads research-fixtures.json and each adapter its adapters/<id>.recorded.json; never declare a live adapter.
45
45
 
46
- Leave client files to the frontend engineer and tools/business-agent definitions to the agentic engineer. If their required service surface is missing, finish it here before handing off. Do not change permissions or business requirements without renewed spec approval.
46
+ Leave client files to the frontend engineer and tools/business-agent definitions to the agentic engineer. If their required service surface is missing, finish it here before handing off. Implement only what the approved spec states. Never add an error code, field, permission, state or behaviour it does not define, not even as the cautious choice: ask for it with a questions block (Session) and leave it unbuilt.
@@ -16,12 +16,10 @@ You own specification decisions and locale terminology, never implementation. Us
16
16
 
17
17
  Write schemaVersion 2: entities with typed fields (never id, tenantId or createdAt) and states, screens, actions, widgets, settings, agentTools, plus outOfScope and decisions. Fill decisions for every choice, including the platform defaults you proposed. The capability card is closed: anything it lists as missing goes to outOfScope with the business decision, never into a scenario. v1 specs stay valid.
18
18
 
19
- When a decision is missing, end the reply with exactly one fenced block tagged questions holding {"questions":[{"id":"Q-1","question":"...","options":["..."],"recommended":"...","allowFreeText":true}]} and nothing after it. Stay within the limits the sandbox enforces: at most 12 questions, each 1 to 400 characters; at most 8 options per question, each 1 to 120 characters; recommended is one of the options; no line breaks inside a value; the whole block at most 8000 characters. A block outside them comes back to you once with the reason. The operator answers in a form and the replies arrive next turn as a Decisions section.
20
-
21
19
  For an edit, compare against base/modules/<dir>/spec/module.yaml and make the smallest delta covering the brief. Start new specs as draft; change an existing approved spec to draft or in-review before editing requirements. Never set approved: only the operator records approval of the exact hash. Later edits invalidate it.
22
20
 
23
21
  State actors, records, ownership, permissions, uniqueness, failure behavior and observable acceptance scenarios. Do not invent business facts. Include success, denial and cross-tenant cases. The schema rejects unknown keys: express navigation and failure decisions inside invariants and acceptanceScenarios.
24
22
 
25
23
  Put the primary entity's read/manage permissions first: the scaffold builds that entity, while later permissions only become constants. Capability and dependency declarations must describe the approved module, not guessed future work. Define matching terminology for each declared locale.
26
24
 
27
- Do not write TypeScript, module.json or package.json. Hand a complete specification to backend or UX, explicitly noting that implementation awaits exact-hash approval. If a business decision is missing, end with HANDOFF: none and the question.
25
+ Do not write TypeScript, module.json or package.json. Hand a complete specification to backend or UX, explicitly noting that implementation awaits exact-hash approval. If a business decision is missing, ask it with a questions block (Session) and end with HANDOFF: none.
@@ -25,4 +25,4 @@ Use the canonical createClientContribution entry. Navigation must point at an ex
25
25
 
26
26
  Records own the page, with create/edit in a Drawer. Reuse TableCard and Table, including widths, loading and empty states. Use translated copy, all five states, and no hardcoded design values. Inspect the rendered screen before handoff.
27
27
 
28
- For TSRX, loop keys can read only the loop item: precompute a key on each item if it needs props or local state. Test pure mapping/filtering logic in .ts helpers. Ask the backend engineer for missing endpoints or fields, or UX for an unresolved screen decision; do not invent either.
28
+ For TSRX, loop keys can read only the loop item: precompute a key on each item if it needs props or local state. Test pure mapping/filtering logic in .ts helpers. Ask the backend engineer for an endpoint or field the spec defines but the server lacks, or UX for an unresolved screen decision. Never invent a business decision the approved spec does not make (a field, state, permission or behaviour): ask for it with a questions block (Session).
@@ -20,4 +20,4 @@ Specify loading, empty, error, populated and denied states. Use TableCard with a
20
20
 
21
21
  Use shared primitives and tokens. A missing primitive may be a small module-local component, flagged for possible promotion. Do not restyle ui-\* classes. Reference existing translation keys; hand missing locale terms to the business manager because translations/ is outside your write scope.
22
22
 
23
- Inspect the rendered result for overflow, alignment and duplicate labels. Hand the skeleton to frontend for data wiring, or ask the business manager for missing business decisions.
23
+ Inspect the rendered result for overflow, alignment and duplicate labels. Hand the skeleton to frontend for data wiring. Ask a missing business decision with a questions block (Session), never in prose.
@@ -50,7 +50,8 @@ profiles:
50
50
  # Who takes the first sandbox turn (planning.ts classifyByRules) and how the
51
51
  # next role is chosen (planHandoff): the HANDOFF line when it names a
52
52
  # registered role, otherwise routeRole by module state, and a failed gate
53
- # always returns to the same role.
53
+ # goes to the role whose write paths cover the file its fix goes in
54
+ # (gate-repair.ts).
54
55
  routing:
55
56
  new-module: business-manager
56
57
  edit-module: business-manager
@@ -33,7 +33,7 @@ sandbox:
33
33
  messageLength: 1 to 20000 characters (packages/sandbox/src/server/turns.ts)
34
34
  briefLength: at least 8 characters (planning.ts assertBrief)
35
35
  gateTimeout: 5 minutes per gate, output capped at 12000 characters (gates.ts)
36
- gateFailure: the same role repairs; at most maxRepairLoops consecutive repair turns per chain, then the chain returns to the operator
36
+ gateFailure: a role whose write paths cover the failing file repairs, a repair that changed nothing is not repeated by the same role, and a gate that failed runs after every turn until it passes; at most maxRepairLoops consecutive repair turns per chain, then the chain returns to the operator
37
37
  byokReads: 400 listed files, 128 KB per read (packages/coding-agent/src/drivers/byok.ts)
38
38
  review:
39
39
  chainedTurns: stop and read the transcript after four automatic handoffs on one brief
@@ -17,5 +17,5 @@ CREATE INDEX IF NOT EXISTS catalog_items_tenant_sku_idx
17
17
  ALTER TABLE catalog_items ENABLE ROW LEVEL SECURITY;
18
18
  ALTER TABLE catalog_items FORCE ROW LEVEL SECURITY;
19
19
  CREATE POLICY catalog_items_tenant_policy ON catalog_items
20
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
21
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
20
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
21
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
@@ -16,5 +16,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS catalog_items_history_tenant_record_version_id
16
16
  ALTER TABLE catalog_items_history ENABLE ROW LEVEL SECURITY;
17
17
  ALTER TABLE catalog_items_history FORCE ROW LEVEL SECURITY;
18
18
  CREATE POLICY catalog_items_history_tenant_policy ON catalog_items_history
19
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
20
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
19
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
20
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
@@ -32,5 +32,5 @@ ON CONFLICT DO NOTHING;
32
32
  ALTER TABLE catalog_items_history_v2 ENABLE ROW LEVEL SECURITY;
33
33
  ALTER TABLE catalog_items_history_v2 FORCE ROW LEVEL SECURITY;
34
34
  CREATE POLICY catalog_items_history_v2_tenant_policy ON catalog_items_history_v2
35
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
36
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
35
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
36
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
@@ -15,5 +15,5 @@ CREATE INDEX IF NOT EXISTS catalog_idempotency_ledger_tenant_operation_idx
15
15
  ALTER TABLE catalog_idempotency_ledger ENABLE ROW LEVEL SECURITY;
16
16
  ALTER TABLE catalog_idempotency_ledger FORCE ROW LEVEL SECURITY;
17
17
  CREATE POLICY catalog_idempotency_ledger_tenant_policy ON catalog_idempotency_ledger
18
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
19
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
18
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
19
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
@@ -13,11 +13,11 @@
13
13
  "dependencies": [
14
14
  {
15
15
  "id": "system.core",
16
- "range": "^0.8.0"
16
+ "range": "^0.9.0"
17
17
  },
18
18
  {
19
19
  "id": "auth.core",
20
- "range": "^0.13.0"
20
+ "range": "^0.14.0"
21
21
  },
22
22
  {
23
23
  "id": "exports.core",
@@ -33,5 +33,5 @@
33
33
  "tenancy": "required",
34
34
  "locales": ["en", "pl"],
35
35
  "stability": "experimental",
36
- "platformApi": "^0.1.0"
36
+ "platformApi": "^0.2.0"
37
37
  }
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "repository": {
32
32
  "type": "git",
33
- "url": "git+https://github.com/Flowdular/official-modules.git",
34
- "directory": "modules/catalog"
33
+ "url": "git+https://github.com/Flowdular/flowdular.git",
34
+ "directory": ".ai/references/catalog"
35
35
  },
36
36
  "files": [
37
37
  "src",
@@ -12,9 +12,9 @@ capabilities:
12
12
  - translations
13
13
  dependencies:
14
14
  - id: system.core
15
- range: ^0.8.0
15
+ range: ^0.9.0
16
16
  - id: auth.core
17
- range: ^0.13.0
17
+ range: ^0.14.0
18
18
  - id: exports.core
19
19
  range: ^0.2.0
20
20
  requires:
@@ -26,7 +26,7 @@ locales:
26
26
  - pl
27
27
  invariants:
28
28
  - Persistence runs on the shared asynchronous database contract. The module receives a leased PostgreSQL handle from platform composition, never a driver or a connection string, and declares explicit PostgreSQL SQL for every statement and migration.
29
- - PostgreSQL item, history, and idempotency ledger tables enable and force row-level security with USING and WITH CHECK policies bound to transaction-local coreloom.tenant_id, and the runtime role holds neither SUPERUSER nor BYPASSRLS. Migrations use a separate lease.
29
+ - PostgreSQL item, history, and idempotency ledger tables enable and force row-level security with USING and WITH CHECK policies bound to transaction-local flowdular.tenant_id, and the runtime role holds neither SUPERUSER nor BYPASSRLS. Migrations use a separate lease.
30
30
  - Every catalog item is owned by exactly one tenant and every query uses the trusted tenant identifier.
31
31
  - SKU is unique inside a tenant and is never used as tenancy authority.
32
32
  - Monetary values are stored as integer minor units with an explicit ISO currency code.
@@ -47,7 +47,7 @@ export function CatalogItemForm(props: CatalogItemFormProps) @{
47
47
  name="name"
48
48
  value={name}
49
49
  onInput={(event) => setName(event.currentTarget.value)}
50
- minlength={2}
50
+ minLength={2}
51
51
  maxLength={160}
52
52
  autoFocus
53
53
  required
@@ -113,7 +113,7 @@ export function CatalogItemForm(props: CatalogItemFormProps) @{
113
113
  name="currency"
114
114
  value={currency}
115
115
  onInput={(event) => setCurrency(event.currentTarget.value)}
116
- minlength={3}
116
+ minLength={3}
117
117
  maxLength={3}
118
118
  required
119
119
  />
@@ -26,8 +26,8 @@ CREATE INDEX IF NOT EXISTS catalog_items_tenant_sku_idx
26
26
  ALTER TABLE catalog_items ENABLE ROW LEVEL SECURITY;
27
27
  ALTER TABLE catalog_items FORCE ROW LEVEL SECURITY;
28
28
  CREATE POLICY catalog_items_tenant_policy ON catalog_items
29
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
30
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
29
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
30
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
31
31
  `;
32
32
 
33
33
  export const CATALOG_MIGRATION_002_HISTORY = `CREATE TABLE IF NOT EXISTS catalog_items_history (
@@ -48,8 +48,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS catalog_items_history_tenant_record_version_id
48
48
  ALTER TABLE catalog_items_history ENABLE ROW LEVEL SECURITY;
49
49
  ALTER TABLE catalog_items_history FORCE ROW LEVEL SECURITY;
50
50
  CREATE POLICY catalog_items_history_tenant_policy ON catalog_items_history
51
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
52
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
51
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
52
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
53
53
  `;
54
54
 
55
55
  export const CATALOG_MIGRATION_003_HISTORY_SERVICE_ACTORS = `CREATE TABLE IF NOT EXISTS catalog_items_history_v2 (
@@ -86,8 +86,8 @@ ON CONFLICT DO NOTHING;
86
86
  ALTER TABLE catalog_items_history_v2 ENABLE ROW LEVEL SECURITY;
87
87
  ALTER TABLE catalog_items_history_v2 FORCE ROW LEVEL SECURITY;
88
88
  CREATE POLICY catalog_items_history_v2_tenant_policy ON catalog_items_history_v2
89
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
90
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
89
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
90
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
91
91
  `;
92
92
 
93
93
  export const CATALOG_MIGRATION_004_IDEMPOTENCY_LEDGER = `CREATE TABLE IF NOT EXISTS catalog_idempotency_ledger (
@@ -107,8 +107,8 @@ CREATE INDEX IF NOT EXISTS catalog_idempotency_ledger_tenant_operation_idx
107
107
  ALTER TABLE catalog_idempotency_ledger ENABLE ROW LEVEL SECURITY;
108
108
  ALTER TABLE catalog_idempotency_ledger FORCE ROW LEVEL SECURITY;
109
109
  CREATE POLICY catalog_idempotency_ledger_tenant_policy ON catalog_idempotency_ledger
110
- USING (tenant_id = current_setting('coreloom.tenant_id', true))
111
- WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
110
+ USING (tenant_id = current_setting('flowdular.tenant_id', true))
111
+ WITH CHECK (tenant_id = current_setting('flowdular.tenant_id', true));
112
112
  `;
113
113
 
114
114
  export const CATALOG_MIGRATION_005_LIST_INDEXES = `ALTER TABLE catalog_items ADD COLUMN IF NOT EXISTS updated_at BIGINT NOT NULL DEFAULT 0;
@@ -90,7 +90,7 @@ describe('catalog migrations', () => {
90
90
  if (!sql.includes('CREATE TABLE')) continue;
91
91
  expect(sql).toContain('ENABLE ROW LEVEL SECURITY');
92
92
  expect(sql).toContain('FORCE ROW LEVEL SECURITY');
93
- expect(sql).toContain("current_setting('coreloom.tenant_id', true)");
93
+ expect(sql).toContain("current_setting('flowdular.tenant_id', true)");
94
94
  expect(sql).toContain('WITH CHECK');
95
95
  }
96
96
  });
@@ -20,7 +20,7 @@ Two ways to land the same module: the sandbox (a brief, specialist turns, gates
20
20
 
21
21
  With an approved `schemaVersion: 2` spec, the specification is the requirement document and you do not go looking for one. Read the spec, the files on this skill's touch list, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`; `.ai/platform-capabilities.md` answers what the platform provides, and the reference module answers what the code looks like.
22
22
 
23
- Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is `HANDOFF: business-manager - <what is missing>`; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
23
+ Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is a `questions` block the operator answers, and the business manager records an answer that changes the spec for a new approval before you continue; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
24
24
 
25
25
  Every `acceptanceScenarios[]` entry maps to at least one test in `tests/`. A scenario with no test is unfinished work, and the scenario id belongs in the test name so the mapping is readable.
26
26
 
@@ -17,7 +17,7 @@ when: A brief names an existing module, or a sandbox session is labelled edit-mo
17
17
 
18
18
  With an approved `schemaVersion: 2` spec delta, the specification is the requirement document. Read the spec, the module itself, the touch list for the change class below, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`: `.ai/platform-capabilities.md` answers what the platform provides.
19
19
 
20
- Anything the delta does not say is a spec defect, not your decision. Report it back (`HANDOFF: business-manager - <what is missing>` in the sandbox, a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
20
+ Anything the delta does not say is a spec defect, not your decision. Report it back (a `questions` block in the sandbox, which the business manager turns into a spec delta for a new approval when the answer changes the spec; a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
21
21
 
22
22
  The spec-element to file mapping is the table in `module-new`; the change classes below are the same mapping arranged by what you are changing.
23
23
 
@@ -99,6 +99,6 @@ Complexity to state in the review: for each new data structure and loop on a req
99
99
  ## Pitfalls
100
100
 
101
101
  - `LIKE` or `=` against `lower(column)` cannot use a plain `(tenant_id, column)` index; store a normalized column (`sku_normalized`) as `.ai/references/catalog` does, or add an expression index on `lower(column)`.
102
- - `ORDER BY lower(name)` (`Flowdular/official-modules`, `modules/parties`) cannot use the `(tenant_id, name, id)` index for the sort; acceptable at current sizes, name it if parties grow.
102
+ - `ORDER BY lower(name)` cannot use a `(tenant_id, name, id)` index for the sort; acceptable at small sizes, name it once the table grows.
103
103
  - A `Kpi` that shows `items.length` after loading the full list is O(rows) network per dashboard load.
104
104
  - Never change behaviour in a performance commit; keep the functional tests green and add none that assert internal call counts.
@@ -14,7 +14,7 @@ Two ways to land the same module: the sandbox (a brief, specialist turns, gates
14
14
 
15
15
  With an approved `schemaVersion: 2` spec, the specification is the requirement document and you do not go looking for one. Read the spec, the files on this skill's touch list, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`; `.ai/platform-capabilities.md` answers what the platform provides, and the reference module answers what the code looks like.
16
16
 
17
- Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is `HANDOFF: business-manager - <what is missing>`; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
17
+ Anything the spec does not say is a spec defect, not a decision you make. A missing field, an unstated conflict behaviour, an undefined state transition, a screen without columns: report it back. In the sandbox that is a `questions` block the operator answers, and the business manager records an answer that changes the spec for a new approval before you continue; on a host it is a question to the user. Never fill the gap with a plausible guess, and never implement anything listed in `outOfScope[]`.
18
18
 
19
19
  Every `acceptanceScenarios[]` entry maps to at least one test in `tests/`. A scenario with no test is unfinished work, and the scenario id belongs in the test name so the mapping is readable.
20
20
 
@@ -10,7 +10,7 @@ description: >-
10
10
 
11
11
  With an approved `schemaVersion: 2` spec delta, the specification is the requirement document. Read the spec, the module itself, the touch list for the change class below, and `.ai/references/catalog` for shape. Do not scan `modules/` or `packages/`: `.ai/platform-capabilities.md` answers what the platform provides.
12
12
 
13
- Anything the delta does not say is a spec defect, not your decision. Report it back (`HANDOFF: business-manager - <what is missing>` in the sandbox, a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
13
+ Anything the delta does not say is a spec defect, not your decision. Report it back (a `questions` block in the sandbox, which the business manager turns into a spec delta for a new approval when the answer changes the spec; a question to the user on a host) instead of guessing, and never implement an item the spec parks in `outOfScope[]`. Every new or changed `acceptanceScenarios[]` entry maps to at least one test, with the scenario id in the test name.
14
14
 
15
15
  The spec-element to file mapping is the table in `module-new`; the change classes below are the same mapping arranged by what you are changing.
16
16
 
@@ -93,6 +93,6 @@ Complexity to state in the review: for each new data structure and loop on a req
93
93
  ## Pitfalls
94
94
 
95
95
  - `LIKE` or `=` against `lower(column)` cannot use a plain `(tenant_id, column)` index; store a normalized column (`sku_normalized`) as `.ai/references/catalog` does, or add an expression index on `lower(column)`.
96
- - `ORDER BY lower(name)` (`Flowdular/official-modules`, `modules/parties`) cannot use the `(tenant_id, name, id)` index for the sort; acceptable at current sizes, name it if parties grow.
96
+ - `ORDER BY lower(name)` cannot use a `(tenant_id, name, id)` index for the sort; acceptable at small sizes, name it once the table grows.
97
97
  - A `Kpi` that shows `items.length` after loading the full list is O(rows) network per dashboard load.
98
98
  - Never change behaviour in a performance commit; keep the functional tests green and add none that assert internal call counts.
@@ -77,8 +77,7 @@ release. No direct registry installation path remains.
77
77
  Automation that imported `installModule` from `flowdular/distribution` must use
78
78
  the host CLI plan and apply commands; that direct install export was removed.
79
79
 
80
- The old `official-modules` Sandbox delivery target was removed. Change
81
- `sandbox.delivery.targets` to `workspace` or `git-pr`; `git-pr` points to the
80
+ Sandbox delivery targets are `workspace` and `git-pr`; `git-pr` points to the
82
81
  platform repository configured in `flowdular.json`. A catalog publisher can
83
82
  use any Git repository and publish immutable artifacts independently. Historical
84
83
  review and RFC documents retain the old project name as provenance.
@@ -2,7 +2,7 @@
2
2
 
3
3
  A module is a self-contained slice of the product: its own permissions,
4
4
  endpoints, migrations, services, screens, translations and tests, wired into the
5
- platform without touching a core file. `.ai/references/catalog` is the pinned reference
5
+ platform without touching a core file. `.ai/references/catalog` is the reference
6
6
  implementation; copy its shape.
7
7
 
8
8
  ## Lifecycle
@@ -419,4 +419,4 @@ RuleSync generates the discovery copies for supported coding agents:
419
419
  `test-hardening`, `cli-extension`, `agent-tool-design`,
420
420
  `business-agent-design`, `workflow-development`, `release-eject-pr`.
421
421
 
422
- Official business modules are maintained outside core. See [module distribution](module-distribution.md) for install, update, lock verification and release checks.
422
+ Business modules kept outside this repository install through [module distribution](module-distribution.md), which covers install, update, lock verification and release checks.
@@ -336,7 +336,13 @@ and a human review remain the repository's own gate.
336
336
  ## Decisions the specialist needs
337
337
 
338
338
  A specialist that cannot continue without a business decision ends its reply
339
- with one fenced block tagged `questions` holding a single JSON object:
339
+ with one fenced block tagged `questions` holding a single JSON object. An
340
+ implementer (every role but the business manager) asks this way for anything
341
+ the approved specification does not decide, such as a new error code, field,
342
+ permission, state or changed behaviour, and leaves that part unbuilt instead of
343
+ deciding it and mentioning it in prose. Every turn's instruction carries the
344
+ format and the limits below from `questions.ts`, the module that parses the
345
+ block.
340
346
 
341
347
  ````
342
348
  ```questions
@@ -389,8 +395,11 @@ POST /sandbox/api/sessions/:id/answers
389
395
  ```
390
396
 
391
397
  behind the same origin, header and ownership checks as every other mutation. It
392
- clears `pendingQuestions` and starts the next turn in the role that asked, in
393
- the module it asked about, with the decisions leading the request text:
398
+ clears `pendingQuestions` and starts the next turn in the module the questions
399
+ were about, with the decisions leading the request text. The business manager's
400
+ own questions go back to it. An implementer's questions go to the business
401
+ manager first (`answeringRole` in `planning.ts`), and so does an answer the
402
+ operator types in the message box instead:
394
403
 
395
404
  ```
396
405
  Decisions:
@@ -406,6 +415,35 @@ INVALID_INPUT` for a body that leaves a question unanswered, names a question
406
415
  the session did not ask, exceeds 400 characters, or gives an answer that is not
407
416
  one of the offered options when the specialist allowed no free text.
408
417
 
418
+ ### Answers to an implementer's questions
419
+
420
+ The business manager applies the answers to `spec/module.yaml`, and the text it
421
+ leaves behind decides what happens next:
422
+
423
+ - An answer that changes what the module must do is recorded in the
424
+ specification, which goes back to `draft`. Its hash no longer matches the
425
+ approval, so the session waits in `awaiting-approval` with the implementer
426
+ that asked as the next role, and implementation is refused until the operator
427
+ approves the new hash. Approving resumes that implementer with its decisions.
428
+ - An answer the approved text already decides leaves the file untouched. The
429
+ approval still holds, and the implementer that asked continues at once with
430
+ its decisions.
431
+
432
+ The wait is read from the transcript (`specFollowUp` in `planning.ts`): the
433
+ newest handoff that is not the business manager's own is the implementer's
434
+ question, so the implementer still resumes when the business manager asks a
435
+ question of its own in between. A gate the implementer left failing runs again
436
+ on the business manager's turn. When it still fails, only a repair the business
437
+ manager takes in that module runs first; any other waits until the implementer
438
+ has resumed with its decisions, and the gates run again after that turn.
439
+
440
+ The `module-rules` gate backs the rule for permissions: `permissions-specified`
441
+ fails a module whose `src/acl/permissions.ts`, or an inline `permission:`
442
+ value, names a permission the specification does not list. Error codes have no
443
+ structured list in a specification and the shipped modules throw many codes
444
+ their specifications never name, so a matching rule for them would fail correct
445
+ modules; the instruction and the question card cover them.
446
+
409
447
  ## Operator commands
410
448
 
411
449
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-flowdular",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "description": "Scaffold a Flowdular application: the platform, one example module and the secrets a fresh install needs.",
6
6
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "dependencies": {
17
17
  "octane": "0.9.1",
18
18
  "segment-state": "0.4.0",
19
- "@flowdular/sdk": "0.6.1"
19
+ "@flowdular/sdk": "0.6.3"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@tsrx/typescript-plugin": "0.3.120",
@@ -22,10 +22,10 @@
22
22
  "build": "flowdular module sync --apply && pnpm --filter @app/platform build"
23
23
  },
24
24
  "devDependencies": {
25
- "@flowdular/sandbox": "0.6.1",
25
+ "@flowdular/sandbox": "0.6.3",
26
26
  "@tsrx/prettier-plugin": "0.3.120",
27
27
  "prettier": "3.6.2",
28
- "flowdular": "0.6.1",
28
+ "flowdular": "0.6.3",
29
29
  "rulesync": "16.21.0"
30
30
  }
31
31
  }
@@ -15,7 +15,7 @@
15
15
  "@octanejs/vite-plugin": "0.2.1",
16
16
  "octane": "0.9.1",
17
17
  "pg": "8.23.0",
18
- "@flowdular/sdk": "0.6.1"
18
+ "@flowdular/sdk": "0.6.3"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@octanejs/app-core": "0.1.1",
@@ -1,65 +0,0 @@
1
- {
2
- "id": "catalog.core",
3
- "version": "0.8.2",
4
- "repository": "Flowdular/official-modules",
5
- "sourceCommit": "f38a67718c5a29aba5b5d37c0504430a3c7f565b",
6
- "artifactSha256": "149808831d620ac0ebc50abb6b0fb2caef6bec66b5d7821c752ec811e5d9219f",
7
- "files": {
8
- "LICENSE": "155d722071bad9d0d832482e06fd5a47f7034389cb63aabcb39f4282aa3499fc",
9
- "migrations/0001_catalog_core.down.sql": "0962a1edf0bde959cd4facccf77bd5b634d6cc25f125a0c79a61770c8871093f",
10
- "migrations/0001_catalog_core.up.sql": "602ed9c1852b729cf278cf8536f79e3f7432f23a5a60c50d8826f5c1b9442d18",
11
- "migrations/0002_catalog_history.down.sql": "7f163e11ca9033101e3bb1de61481b1a8043c204e65aa2bb508a13b065e98c78",
12
- "migrations/0002_catalog_history.up.sql": "3aa30993b1676cf357c2ef87f19a7d4b64b77041c0e4bc743fced04521471c28",
13
- "migrations/0003_catalog_history_service_actors.down.sql": "f20ecc8d7d753af3d2b6fdbff9d637fd938884cfbd88b08a30958e6aa000132b",
14
- "migrations/0003_catalog_history_service_actors.up.sql": "7caae787ca2fc1e331ccbfda4df5982beec76136e8dc486aab5532ccd338a722",
15
- "migrations/0004_catalog_idempotency_ledger.down.sql": "8ba72d8edc4d25ecf6d041888cf321690c25afdaf3723812ddd7d391d75370aa",
16
- "migrations/0004_catalog_idempotency_ledger.up.sql": "41e86ba2051159c6cc9672bfae17c1d02051da975f1c43c566a2b66592673cb0",
17
- "migrations/0005_catalog_list_indexes.down.sql": "3dd547d738e75513abef502afc4bf9b51851ec9405b6b719c6134b897c5b1776",
18
- "migrations/0005_catalog_list_indexes.up.sql": "dc3ece30b93fba0c91be58f772d1ae421cfbba49439e8c72a06aead6720f5db5",
19
- "migrations/README.md": "2a15fd001713c2552a3c82b186246aa5fec136f43143cc2d9aa15bd491a09d41",
20
- "module.json": "d2a98b70d60a433e1b3b6547352781048d562b996e3ee961f519d61ee1b623b9",
21
- "package.json": "c23a99016f974d183189a05e4cfc4929788a46ae1ad65c623d66513e0880cdbd",
22
- "spec/module.yaml": "992953d002574e83374c21e1ee7bef1d451c04b0180892856838d7c67404ce66",
23
- "src/acl/permissions.ts": "3375521a5a229736ffac5a948140ec347dc7a7e4fba80e778c0baaf9e0622590",
24
- "src/agent/tools.ts": "3403db7954906dc2c79227ba0420b5cb4bfb57063b7cfc285e6e556f16be9266",
25
- "src/api/endpoints.ts": "205ef36d058f246f99b77336e7246a23aaca611c696a1f6f09758f66e8a93a29",
26
- "src/api/list-cursor.ts": "dcb763edc0128a3aac95e9ca3c5158611a7f2c6a4c71484438c89b7f4d79bb0d",
27
- "src/client/CatalogHistoryDrawer.tsrx": "6cdba5249be81e70da703cb34c1a2210943ce5e5fb596ee77cf7952e2acf3ee3",
28
- "src/client/CatalogItemForm.tsrx": "d621ac2a513635a5e38ee44726c07926bf035ec5e0dddca487c462cc7913d040",
29
- "src/client/CatalogView.tsrx": "2c3e49bb1e54b58d636de0ddbb6ece429acf6aeadb6a0515ab52fca3baabec21",
30
- "src/client/api.ts": "eaa55af81d26aa0190d19b3102c363c1ee25b2bdc05436446ac95dcde62aea75",
31
- "src/client/contribution.tsrx": "6cbf79e6188bdf24b9cec4a06ae621e03efd5d0c76ad72b28828eee9155ab893",
32
- "src/client/index.ts": "03eb0664cdafccb66cb25f2e1b07e6959c2dfa9bdbfffc3e7edf9b535ba4949a",
33
- "src/client/navigation-copy.ts": "9a8757e64f4001a93e2bc2861c686a19f791f9d67a396d9e658023b1ec4cea8f",
34
- "src/client/state.ts": "61601f6037c4bb8a709b69b10c1a37e59b45b0c941240c436f7861c2b034dcc1",
35
- "src/domain/lists.ts": "83749967f99fa0c4f44abc0c614108b844321e50ce6408553215e6233ad6e350",
36
- "src/domain/types.ts": "374efeb24c4f7d41e3c660336e721fa362418579837d44a46724076d03287a0b",
37
- "src/domain/variables.ts": "131130e57838235b1f3fcb799da44baeae16522bb346d522827e022305c110b5",
38
- "src/index.ts": "5b27943018db9a18651d62add7d6f8397d7c492a204381fae74547b99b91990d",
39
- "src/platform.ts": "f048082a33c1c688e4952750c762c8b65a4626ff52cc9c4eaca2156014bac631",
40
- "src/server/index.ts": "90eae107d863418124e5d10c4d1fe8a119bd14da605b36de708c18d8500c4b5e",
41
- "src/server/runtime.ts": "5f4389a6adf8265f6737c489baf686f63cc3550662103d28b2da9800dd9f5b63",
42
- "src/services/catalog-service.ts": "66e61dfbd9797d31e6814c18efcd21cfcb7b220f7df22677868f486f3fa0e9d1",
43
- "src/services/data-classes.ts": "ea09b1a7def59fee43d57ca7dab6fdb4d646b51df2cacb60af96676c43602b33",
44
- "src/services/database-repository.ts": "1b72ce91a2f85f6572825766781a806d94fe0d2abb91872ee9acae3b1e70db2e",
45
- "src/services/index.ts": "a08aefe5101814538666f861536287fc382e6c655d62ba9b9ef4bbfbc6ede4af",
46
- "src/services/item-export.ts": "b2a4613b43a98d0d41699481bb5e85a770f9a60cb2241579b065effb6936c80b",
47
- "src/services/migration.ts": "57c9a857d4074973e14b5e3a1c4548a92ad0faca371419e7daf2334f3ef701ab",
48
- "src/services/repository.ts": "9f560033875d05654148b4a11897465ee4eefa0d7fa701439e8f562da9fba1db",
49
- "src/services/target-idempotency.ts": "7111b56a30b691eaaaa64f5691895ac94b6e0735b0079794835bbbeba5102cb0",
50
- "tests/agent-tools.test.ts": "7762c14bc353ee3085df46a91cf370eb5c25b2edb7096f0a4b0e033f220ea726",
51
- "tests/client-state.test.ts": "ea146c793b14d0f9bc5e36d92e92894ced6531b8fcbd11c8be1486b62313b8c3",
52
- "tests/data-classes.test.ts": "bea08e4d1d7380ccdebc211374b74a6034714b192fd98bfb90a2218067b35658",
53
- "tests/endpoints.test.ts": "a2d700f4c3eb6fbbef5c57ed5591017a27c98e17fe84fba8426fcd3a2820b210",
54
- "tests/export.test.ts": "de83066272cee5f7f5736d636d7b9b97dab09778ba661816e401bf926b826402",
55
- "tests/idempotency.test.ts": "faea4a2cfa04e81b7155399cba807af4c1ba4448cdfeab733d1afe801d27734f",
56
- "tests/list.test.ts": "97605b50020841cbdac62f9d44b65f0f7dce9c4c4972af6409afeb6b9b66e59a",
57
- "tests/migrations.test.ts": "fb796aecedb997f6395c2c15e45bf4abfae4677953fa8cb420c94e9cfba8222f",
58
- "tests/module.test.ts": "af961a5bcddc41d304d14841f8810976f43f46b46ab7814142fdb921a773e92a",
59
- "tests/support/database.ts": "4ff6d093ca2e80baab3dea476018661473d6474db63d67655f1edc667b8472ac",
60
- "translations/en.json": "a86d70e02ccf46a2a132d5bee0de7c528c0eb56a85c269a78e0c2e7e0de24e37",
61
- "translations/pl.json": "8157d83467e9dd8d9700e2fb188f1a730073f805d2a8b3f0ba98f02f2ca9a264",
62
- "tsconfig.json": "140bb4775df421146563d13d2f78ff74cb3c2decab6737db32938339248a92ba",
63
- "vitest.config.ts": "d13725b13c3712ec91c1646e9226fb172eec2599f72f4e6608bece9912e2bd81"
64
- }
65
- }