arkgate 4.8.3 → 4.8.5
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 +279 -1
- package/README.md +17 -7
- package/bin/ark-check-runtime.mjs +340 -5
- package/bin/ark-layer-match.mjs +170 -13
- package/bin/ark-mcp-runtime.mjs +9 -2
- package/bin/lib/agent-homes.mjs +41 -6
- package/bin/lib/analysis-completeness.mjs +86 -0
- package/bin/lib/analysis-engine.mjs +8 -8
- package/bin/lib/architecture-scan.mjs +2 -0
- package/bin/lib/ark-order-invariants.mjs +37 -0
- package/bin/lib/ark-order-sensors.mjs +4 -0
- package/bin/lib/arkrules-contract.mjs +8 -1
- package/bin/lib/check-args.mjs +68 -0
- package/bin/lib/config-contract.mjs +26 -0
- package/bin/lib/design-smells.mjs +85 -0
- package/bin/lib/diagnostic-catalog.mjs +9 -1
- package/bin/lib/first-run-help.mjs +16 -4
- package/bin/lib/invariant-coverage-io.mjs +175 -19
- package/bin/lib/invariant-coverage.mjs +110 -7
- package/bin/lib/literal-path-drift-io.mjs +569 -0
- package/bin/lib/literal-path-drift.mjs +761 -0
- package/bin/lib/policy-delta-io.mjs +5 -0
- package/bin/lib/remediation.mjs +25 -1
- package/bin/lib/rules-under-contract.mjs +5 -0
- package/bin/lib/scan-files.mjs +54 -0
- package/bin/lib/sensor-promote-cli.mjs +372 -0
- package/bin/lib/sensor-promote-io.mjs +246 -0
- package/bin/lib/sensor-promotion.mjs +363 -0
- package/bin/lib/skill-catalog-apply.mjs +18 -1
- package/bin/lib/skill-install.mjs +4 -3
- package/bin/lib/upgrade-whats-new.mjs +1 -1
- package/dist/{configTypes-dNJ2C0yx.d.ts → configTypes-dy5PfTqS.d.ts} +31 -0
- package/dist/{diagnosticCatalog-C5GgeyEE.d.ts → diagnosticCatalog-DMO30svh.d.ts} +75 -7
- package/dist/eslint/index.cjs +5 -5
- package/dist/eslint/index.d.ts +34 -1
- package/dist/eslint/index.js +5 -5
- package/dist/index.cjs +30 -30
- package/dist/index.d.ts +68 -5
- package/dist/index.js +29 -29
- package/dist/nestjs/index.cjs +5 -5
- package/dist/nestjs/index.d.ts +3 -3
- package/dist/nestjs/index.js +5 -5
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.d.ts +11 -2
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +11 -11
- package/dist/runtime/index.d.ts +30 -7
- package/dist/runtime/index.js +11 -11
- package/dist/{types-dK24fDZa.d.ts → types-BuM8WNqe.d.ts} +1 -1
- package/dist/{types-DeK7SYGC.d.ts → types-CzE6LMaW.d.ts} +2 -2
- package/docs/README.md +5 -4
- package/docs/agent-guide.md +186 -4
- package/docs/ai-gates.md +13 -2
- package/docs/arkorder.md +210 -0
- package/docs/configuration.md +88 -5
- package/docs/develop.md +4 -2
- package/docs/diagnostics.md +97 -1
- package/docs/enthusiast/how-to-agent-gates.md +1 -1
- package/docs/package-surface.md +37 -5
- package/docs/use.md +1 -1
- package/package.json +3 -2
- package/schemas/ark.config.schema.json +63 -0
- package/server.json +3 -3
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +5 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +1 -0
- package/templates/agent-skills/ark-upgrade/SKILL.md +1 -1
- package/templates/skills/ark-adopt.md +5 -0
- package/templates/skills/ark-coverage.md +1 -0
- package/templates/skills/ark-upgrade.md +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-
|
|
1
|
+
import { i as Policy, P as PolicyViolation, I as IntentName, j as IntentCreator, k as IntentRelationship, b as ArchitectureProfile, D as DomainEvent, E as EventMetadata, h as PolicyEnforcementMode, A as ArchitectureLayer, c as ArchitectureRule, d as ArkCheckConfig } from './types-BuM8WNqe.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* PolicyEngine
|
|
@@ -1234,4 +1234,4 @@ interface CreateArkKernelFromConfigOptions extends Omit<CreateArkKernelOptions,
|
|
|
1234
1234
|
}
|
|
1235
1235
|
type ArkKernelConfig = ArkCheckConfig;
|
|
1236
1236
|
|
|
1237
|
-
export {
|
|
1237
|
+
export { ARK_RUN_INSPECTOR_EVENTS_PATH as $, type ArkKernel as A, type OutboxStatus as B, type CreateArkKernelOptions as C, type DefineIntentOptions as D, type EventContractRegistry as E, type OutboxRecord as F, type GraphEdge as G, type ObservabilityDriftReport as H, IntentRegistry as I, ARK_RUN_COMPONENT_LIFETIMES as J, ARK_RUN_EPHEMERAL_DEFAULT as K, ARK_RUN_GRAPH_DEFAULT_SLICE as L, type MetadataRegistry as M, ARK_RUN_GRAPH_NODE_KINDS as N, type ObservabilityReporter as O, type ProjectionRegistry as P, ARK_RUN_GRAPH_PROCESS_EDGE_KINDS as Q, type ReadModelStore as R, type SagaContext as S, type TraceRecordType as T, ARK_RUN_GRAPH_SCHEMA_VERSION as U, ARK_RUN_GRAPH_SLICES as V, type WorkflowStore as W, ARK_RUN_GRAPH_TECHNICAL_EDGE_KINDS as X, ARK_RUN_INFORMATION_PACKAGE_SCHEMA_VERSION as Y, ARK_RUN_INSPECTOR_DEFAULT_HOST as Z, ARK_RUN_INSPECTOR_DEFAULT_PORT as _, type DependencyGraph as a, InvalidArkRunSendOptionError as a$, ARK_RUN_INSPECTOR_GRAPH_PATH as a0, ARK_RUN_INSPECTOR_SCHEMA_VERSION as a1, ARK_RUN_INSPECTOR_SNAPSHOT_PATH as a2, ARK_RUN_INSPECTOR_SSE_EVENT as a3, ARK_RUN_INSPECTOR_TRANSPORT_FALLBACK as a4, ARK_RUN_TRANSPORT_KINDS as a5, type ArkManifestArchitecture as a6, type ArkManifestData as a7, type ArkManifestEntityLink as a8, type ArkManifestGraph as a9, type ArkRunInspectorSnapshotInput as aA, type ArkRunInspectorSource as aB, type ArkRunInspectorTransportFacts as aC, type ArkRunPublisher as aD, type ArkRunRegisterOptions as aE, type ArkRunRegistrationHandle as aF, type ArkRunSendOptions as aG, type ArkRunSendPlan as aH, type ArkRunSendPlanInput as aI, type ArkRunSendResult as aJ, type ArkRunTransportKind as aK, type AuditRecordInput as aL, type AuditRecordType as aM, type EntityMeta as aN, type EventContractIssue as aO, type EventHandler as aP, type EventInterceptionInfo as aQ, type EventInterceptor as aR, type EventInterceptorContext as aS, type EventPayloadPatch as aT, type EventPayloadSchema as aU, type EventPublisher as aV, type EventSchemaField as aW, type EventSchemaFieldType as aX, type FieldMeta as aY, type GraphNode as aZ, InvalidArkRunGraphQueryError as a_, type ArkManifestIntent as aa, type ArkManifestPolicy as ab, type ArkManifestProjection as ac, type ArkRunBrokerAdapter as ad, type ArkRunComponentLifetime as ae, type ArkRunDeliveredVia as af, type ArkRunExtendedInfo as ag, type ArkRunGraph as ah, type ArkRunGraphEdge as ai, type ArkRunGraphEdgeKind as aj, type ArkRunGraphMatch as ak, type ArkRunGraphMatchInput as al, type ArkRunGraphNode as am, type ArkRunGraphNodeKind as an, type ArkRunGraphProcessEdgeKind as ao, type ArkRunGraphQuery as ap, type ArkRunGraphResolvedQuery as aq, type ArkRunGraphSlice as ar, type ArkRunGraphTechnicalEdgeKind as as, type ArkRunInformationPackageComponent as at, type ArkRunInspectorBind as au, ArkRunInspectorBindError as av, type ArkRunInspectorBindInput as aw, type ArkRunInspectorHandle as ax, ArkRunInspectorProductionError as ay, type ArkRunInspectorSnapshot as az, type AuditStore as b, type ObservabilityFlow as b0, type ObservedLayerFlowMode as b1, type OutboxStore as b2, type PolicyEvaluationResult as b3, type ProjectionCheckpoint as b4, type ProjectionDefinition as b5, type PublishedEventRecord as b6, type RetryPolicy as b7, type SagaStatus as b8, type SagaStep as b9, type StartArkRunInspectorOptions as ba, type TraceSink as bb, type Unsubscribe as bc, type WorkflowDefinition as bd, type WorkflowStatus as be, type WorkflowStep as bf, arkRunGraphQueryFromSearchParams as bg, arkRunInspectorUrl as bh, buildArkRunInspectorSnapshot as bi, buildDependencyInformationPackage as bj, closeArkRunGraphQuery as bk, closedArkRunEphemeral as bl, closedArkRunTransportKind as bm, formatArkRunGraphMermaid as bn, formatArkRunInspectorSseEvent as bo, isArkRunInspectorLoopbackHost as bp, isArkRunInspectorProductionEnv as bq, requestArkRunGraph as br, resolveArkRunInspectorBind as bs, resolveArkRunSendPlan as bt, startArkRunInspector as bu, type AuditRecord as c, type AuditQuery as d, type CreateAuditTrailOptions as e, type AuditTrail as f, type EventContract as g, type EventContractValidationResult as h, type CreateProjectionRegistryOptions as i, type EventBufferStore as j, type EventBufferRecord as k, type EventBufferStatus as l, type EventBusOptions as m, type EventBus as n, type CreateObservabilityReporterOptions as o, PolicyEngine as p, type ArkManifest as q, type WorkflowSnapshot as r, type SagaDefinition as s, type CreateWorkflowEngineOptions as t, type SagaInstance as u, type WorkflowEngine as v, type DependencyInformationPackage as w, type ArkKernelConfig as x, type CreateArkKernelFromConfigOptions as y, type TraceRecord as z };
|
package/docs/README.md
CHANGED
|
@@ -36,6 +36,7 @@ Product site: [arkgate.online](https://www.arkgate.online/) · npm: [`arkgate`](
|
|
|
36
36
|
| [agent-guide.md](agent-guide.md) | Agent, CLI, and MCP reference (incl. `ark status --json` / MCP `ark_status`) |
|
|
37
37
|
| [diagnostics.md](diagnostics.md) | Public diagnostic `ruleId` catalog (why / fix anchors) |
|
|
38
38
|
| [configuration.md](configuration.md) | `ark.config.json` contract |
|
|
39
|
+
| [arkorder.md](arkorder.md) | Optional ArkOrder extra: library + sensors, not a service |
|
|
39
40
|
| [brownfield-adoption.md](brownfield-adoption.md) | Existing messy repos |
|
|
40
41
|
| [package-surface.md](package-surface.md) | Stable vs experimental package surface |
|
|
41
42
|
| [typescript-support.md](typescript-support.md) | TS 5 / 6 / 7 analysis boundary |
|
|
@@ -45,7 +46,7 @@ Product site: [arkgate.online](https://www.arkgate.online/) · npm: [`arkgate`](
|
|
|
45
46
|
|-----|------------|
|
|
46
47
|
| [CONTRIBUTING.md](../CONTRIBUTING.md) | Setup, rules, PR/release |
|
|
47
48
|
| [ROADMAP.md](../ROADMAP.md) | Live implementation queue (one `doing` at a time). History: [archive/roadmap-history.md](archive/roadmap-history.md) |
|
|
48
|
-
| [adr/](adr/README.md) | Architecture decisions ([0032](adr/0032-writes-via-aggregate-sensor.md) writes-via-aggregate) |
|
|
49
|
+
| [adr/](adr/README.md) | Architecture decisions ([0032](adr/0032-writes-via-aggregate-sensor.md) writes-via-aggregate · [0033](adr/0033-arkorder-runtime-half-is-arkrun.md) ArkOrder runtime half) |
|
|
49
50
|
| [SECURITY.md](../SECURITY.md) · [threat-model.md](threat-model.md) | Security |
|
|
50
51
|
|
|
51
52
|
---
|
|
@@ -57,13 +58,13 @@ These are **not** the day-to-day product path. They stay in the repo for evidenc
|
|
|
57
58
|
| Area | Path |
|
|
58
59
|
|------|------|
|
|
59
60
|
| Release notes (by version) | [releases/](releases/) · npm [CHANGELOG.md](../CHANGELOG.md) (Unreleased + 4.6.x) · [pre-4.6 archive](archive/CHANGELOG-pre-4.6.md) |
|
|
60
|
-
| Epic plans | [plans/](plans/) — maintainer seeds, not required to use the package. Live: [alive-in-six-months](plans/alive-in-six-months/README.md) (`AL01`–`AL04` done; `AL05` parked). [arkrun](plans/arkrun/README.md) (Phase RN; `RN01`–`RN17` done; shipped **4.7.0** + companion **4.7.4**; ADRs [0020](adr/0020-arkrun-gated-extra-plane.md)–[0024](adr/0024-arkrun-transport-ports.md) accepted). [one-catalog-one-root](plans/one-catalog-one-root/README.md) (Phase HS; `HS01`–`HS05` done; shipped **4.7.1**). [arkorder](plans/arkorder/README.md) (Phase OR; `OR01`–`OR07` done; shipped **4.8.0**; extra **inside** package `arkgate` as `arkgate/order`; ADRs [0027](adr/0027-arkorder-gated-extra-plane.md)–[0031](adr/0031-one-package-extras-deprecate-companion.md)). |
|
|
61
|
+
| Epic plans | [plans/](plans/) — maintainer seeds, not required to use the package. Live: [alive-in-six-months](plans/alive-in-six-months/README.md) (`AL01`–`AL04` done; `AL05` parked). [arkrun](plans/arkrun/README.md) (Phase RN; `RN01`–`RN17` done; shipped **4.7.0** + companion **4.7.4**; ADRs [0020](adr/0020-arkrun-gated-extra-plane.md)–[0024](adr/0024-arkrun-transport-ports.md) accepted). [one-catalog-one-root](plans/one-catalog-one-root/README.md) (Phase HS; `HS01`–`HS05` done; shipped **4.7.1**). [arkorder](plans/arkorder/README.md) (Phase OR; `OR01`–`OR07` done; shipped **4.8.0**; extra **inside** package `arkgate` as `arkgate/order`; ADRs [0027](adr/0027-arkorder-gated-extra-plane.md)–[0031](adr/0031-one-package-extras-deprecate-companion.md)). [arkorder-arkrun](plans/arkorder-arkrun/README.md) (Phase XP; `XP01`–`XP08` done on tree; **4.8.5** prepared; ADR [0033](adr/0033-arkorder-runtime-half-is-arkrun.md)). |
|
|
61
62
|
| Claims audit | [audit/claims-matrix.md](audit/claims-matrix.md) |
|
|
62
63
|
| Field adoption kit (scaffolding, not closed) | [field/](field/) |
|
|
63
64
|
| Runtime hardening (experimental) | [production-hardening.md](production-hardening.md) |
|
|
64
65
|
|
|
65
|
-
Current published: [releases/4.8.
|
|
66
|
-
Prior: [releases/4.8.2.md](releases/4.8.2.md) · [releases/4.8.1.md](releases/4.8.1.md) · [4.8.0](releases/4.8.0.md) · [4.7.6](releases/4.7.6.md) · [4.7.5](releases/4.7.5.md) · [4.7.4](releases/4.7.4.md) · [4.7.3](releases/4.7.3.md) · [4.7.2](releases/4.7.2.md) · [4.7.1](releases/4.7.1.md) · [4.7.0](releases/4.7.0.md) · [4.6.7](releases/4.6.7.md) · [4.6.6](releases/4.6.6.md) · [4.6.5](releases/4.6.5.md) · [4.6.4](releases/4.6.4.md) · [4.6.3](releases/4.6.3.md) · [4.6.2](releases/4.6.2.md) · [4.6.1](releases/4.6.1.md) · [4.6.0](releases/4.6.0.md).
|
|
66
|
+
Current tree: [releases/4.8.5.md](releases/4.8.5.md) (`arkgate@4.8.5`, prepared). Current published: [releases/4.8.4.md](releases/4.8.4.md) (`arkgate@4.8.4` on npm `latest`; does not close `K01`).
|
|
67
|
+
Prior: [releases/4.8.3.md](releases/4.8.3.md) · [releases/4.8.2.md](releases/4.8.2.md) · [releases/4.8.1.md](releases/4.8.1.md) · [4.8.0](releases/4.8.0.md) · [4.7.6](releases/4.7.6.md) · [4.7.5](releases/4.7.5.md) · [4.7.4](releases/4.7.4.md) · [4.7.3](releases/4.7.3.md) · [4.7.2](releases/4.7.2.md) · [4.7.1](releases/4.7.1.md) · [4.7.0](releases/4.7.0.md) · [4.6.7](releases/4.6.7.md) · [4.6.6](releases/4.6.6.md) · [4.6.5](releases/4.6.5.md) · [4.6.4](releases/4.6.4.md) · [4.6.3](releases/4.6.3.md) · [4.6.2](releases/4.6.2.md) · [4.6.1](releases/4.6.1.md) · [4.6.0](releases/4.6.0.md).
|
|
67
68
|
Older notes: [releases/](releases/). Config: [configuration.md](configuration.md).
|
|
68
69
|
|
|
69
70
|
---
|
package/docs/agent-guide.md
CHANGED
|
@@ -461,6 +461,23 @@ order (universal): `lint` → `typecheck` → `arkgate-check` / `check:architect
|
|
|
461
461
|
When `include` matches **zero** TS/JS files, plan/doctor treat that as **not done**
|
|
462
462
|
(`goal.emptyScope`, adoption gap `empty-scope`) — never “clean architecture.”
|
|
463
463
|
|
|
464
|
+
The **verdict path refuses** in that state rather than passing: a plain or `--strict`
|
|
465
|
+
`ark-check` over zero governed files exits 1 with `ANALYSIS_COVERS_NO_FILES`, because
|
|
466
|
+
every rule is vacuously satisfied on an empty set. It fires when source exists under the
|
|
467
|
+
analyzed root and the contract governs none of it, or when the analyzed root is not the
|
|
468
|
+
root you asked for (a contract found outside `--root` makes ArkGate adopt the contract's
|
|
469
|
+
directory). A genuinely greenfield repo — no governable source anywhere under the root
|
|
470
|
+
you asked for — still passes, so `ark init` can land a contract before the code.
|
|
471
|
+
|
|
472
|
+
"Source exists" is answered by a probe the contract cannot steer: it ignores `exclude`
|
|
473
|
+
(otherwise `exclude: ["**"]` would buy a green), skips dot-directories, never follows a
|
|
474
|
+
symlink, skips `*.config.*` (a repo whose only TS is `vite.config.ts` is greenfield, not
|
|
475
|
+
a mismatch), and stops at 200 files — the message says *at least N* when it did.
|
|
476
|
+
|
|
477
|
+
The commands below are exempt on purpose: they are how the refusal gets diagnosed and
|
|
478
|
+
fixed, so `--plan`, `--coverage` and `--doctor` still exit 0 on an empty scope and report
|
|
479
|
+
`empty-scope`. **Do not gate CI on a report mode** — gate on `ark-check` / `--strict`.
|
|
480
|
+
|
|
464
481
|
```bash
|
|
465
482
|
npx ark-check --suggest-include --json # workspaces + nested package.json+TS roots
|
|
466
483
|
npx ark-check --adopt-contract --write # expand include + UI patterns (no rule weakening)
|
|
@@ -469,6 +486,167 @@ npx ark-check --coverage
|
|
|
469
486
|
|
|
470
487
|
Polyglot repos: Ark only governs TypeScript/JS. Point include at package roots that have sources.
|
|
471
488
|
|
|
489
|
+
### Which rules can be enforced (`--sensors`, `--promote`)
|
|
490
|
+
|
|
491
|
+
Promotion — moving a rule from `advisory` to `enforced` — used to be discovered
|
|
492
|
+
by trial. Edit the ArkRules JSON, wait for a full run (~160s on a real
|
|
493
|
+
repository), read the result, `git checkout` it back. Four attempts before the
|
|
494
|
+
map was clear, and one of them ended in a rejection naming a sensor id the
|
|
495
|
+
author had never typed: a rule called `types-only` refused with *"sensor
|
|
496
|
+
`no-anemic-model` is Tier-2 advisory-only"*.
|
|
497
|
+
|
|
498
|
+
Both surfaces are read-only by default and neither invents a second opinion:
|
|
499
|
+
they project the same declarations the gate reads.
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
npx ark-check --sensors [--json] # the map: what can ever be enforced
|
|
503
|
+
npx ark-check --promote [--json] # the price: what enforcing would cost, one run
|
|
504
|
+
npx ark-check --promote <ruleId> --apply # write mode "enforced" into that rule's own file
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
**`--sensors`** lists every sensor ArkGate ships — ArkRules, ArkRun and
|
|
508
|
+
ArkOrder — with its plane, its tier and whether it can *ever* be enforced, so
|
|
509
|
+
Tier-2 shows up before you write the rule rather than after you wait for a run.
|
|
510
|
+
It also says *how*: only the ArkRules plane is promoted per rule; ArkRun and
|
|
511
|
+
ArkOrder are switched by the plane-level `arkRun.mode` / `arkOrder.mode`, and
|
|
512
|
+
`--promote --apply` writes ArkRules documents only.
|
|
513
|
+
Underneath it lists every rule the contract actually declares, each with its
|
|
514
|
+
local id, the sensor it delegates to, the layer, the file it was declared in,
|
|
515
|
+
its current mode, and the reason it can or cannot be promoted. Three things
|
|
516
|
+
block a promotion, and the surface names which one fired:
|
|
517
|
+
|
|
518
|
+
- **`tier-2-advisory-only`** — the sensor is a heuristic (`no-anemic-model`,
|
|
519
|
+
`arkrun-skip-resolve`). Advisory forever; the contract rejects `enforced`.
|
|
520
|
+
- **`no-structure-teeth`** — `invariant-coverage` as a *structure* entry emits
|
|
521
|
+
nothing (coverage is judged per entry in `invariants`), so enforcing it would
|
|
522
|
+
change nothing. Promote the invariant instead.
|
|
523
|
+
- **`no-coverage-evidence`** — an invariant whose evidence does not support
|
|
524
|
+
promotion. The text is `canPromoteInvariant`'s own, so this surface can never
|
|
525
|
+
promise a promotion the gate then refuses.
|
|
526
|
+
|
|
527
|
+
It needs no TypeScript and runs no analysis: the contract, the ArkRules
|
|
528
|
+
documents it points at, and the coverage evidence walk (a filesystem walk plus a
|
|
529
|
+
text match — ArkGate never executes a test). Exit 0 on a report, **2** when the
|
|
530
|
+
contract or its ArkRules references will not load, or when the governed-file
|
|
531
|
+
scan itself fails — reporting every invariant as uncovered because ArkGate could
|
|
532
|
+
not collect the inputs would be our limitation printed as a fact about your
|
|
533
|
+
tests.
|
|
534
|
+
|
|
535
|
+
**`--promote`** adds the price. Advisory rules are already evaluated on every
|
|
536
|
+
run, so the findings each one produces are sitting in the analysis that just
|
|
537
|
+
happened, stamped with the rule that produced them: **one** run prices **every**
|
|
538
|
+
declared rule, which is the whole difference from the loop it replaces. A
|
|
539
|
+
promotable advisory rule with zero findings today is a free promotion; one with
|
|
540
|
+
seven is seven findings that stop being warnings and start failing the gate.
|
|
541
|
+
|
|
542
|
+
Findings are counted per `<sourceFile>#<ruleId>`, not per bare id. Rule ids are
|
|
543
|
+
unique inside one ArkRules document, not across them, so two layer files may
|
|
544
|
+
both declare `shared-id` — keyed on the id alone their findings pool and each
|
|
545
|
+
row reports the other's as its own.
|
|
546
|
+
|
|
547
|
+
**A price the run could not measure is never printed as a price.** Two things
|
|
548
|
+
qualify the numbers, and both are named above them rather than left implied:
|
|
549
|
+
|
|
550
|
+
- **Incomplete analysis.** Parse failures suppress findings, so the count is a
|
|
551
|
+
floor, not the cost.
|
|
552
|
+
- **The classification floor.** Below it every enforced ArkRules finding is
|
|
553
|
+
demoted to a warning, so promoting buys a label and not a tooth — the gate
|
|
554
|
+
would still pass. `wouldBlock` drops to zero and the run says so. Classify
|
|
555
|
+
more of the tree (`--coverage`) before promoting.
|
|
556
|
+
|
|
557
|
+
Plan by default — there is no `--dry-run` anywhere in `bin/`. `--apply` needs
|
|
558
|
+
one named rule id: `--promote <ruleId> --apply`, or `--promote=<ruleId>` when
|
|
559
|
+
the id starts with `-`. It refuses a bare `--promote --apply` rather than
|
|
560
|
+
rewriting the contract in bulk behind a single flag, refuses an id declared in
|
|
561
|
+
two documents rather than silently writing the first, and refuses to make a
|
|
562
|
+
contract change on a cost this run did not measure. `--promote` cannot be
|
|
563
|
+
combined with a mode that answers first (`--sensors`, `--coverage`, `--plan`,
|
|
564
|
+
`--doctor`, …) — that printed the report and exited 0 having written nothing —
|
|
565
|
+
nor with `--changed` / `--against` / `--baseline`, which narrow or suppress the
|
|
566
|
+
findings the price is made of.
|
|
567
|
+
|
|
568
|
+
The write binds to the rule that was priced (an edit that changed its sensor in
|
|
569
|
+
between is refused), writes every byte before it truncates so a failed write
|
|
570
|
+
cannot leave the project without a loadable contract, and names its refusals:
|
|
571
|
+
`symlink`, `hard-link`, `not-utf8`, `outside-root`, `short-write`. A document
|
|
572
|
+
that was already indented keeps its indentation and trailing newline; a minified
|
|
573
|
+
one comes back pretty-printed, because the write is a JSON round-trip rather
|
|
574
|
+
than a targeted text edit. Exit 0 for a preview or a successful write, 1 for an
|
|
575
|
+
unknown rule id or a refused write, 2 for bad arguments or ArkRules references
|
|
576
|
+
that will not load.
|
|
577
|
+
|
|
578
|
+
### Literal path drift after a rename (`--path-drift`)
|
|
579
|
+
|
|
580
|
+
A repo path written inside a **string, a comment or a docstring** is invisible to
|
|
581
|
+
the rest of the gate: `tsc` resolves imports, not strings, and ESLint does not
|
|
582
|
+
either. A rename therefore compiles green and the reference lies afterwards.
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
npx ark-check --path-drift --base-ref origin/main # preview
|
|
586
|
+
npx ark-check --path-drift --base-ref origin/main --write # apply the anchored fixes
|
|
587
|
+
npx ark-check --path-drift --base-ref origin/main --all # + the unanchored sweep
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Two modes, because they make different claims:
|
|
591
|
+
|
|
592
|
+
- **Anchored** (default) — the referenced path is gone and exactly one rename in
|
|
593
|
+
`git diff --find-renames <base-ref>` says where it went. A finding
|
|
594
|
+
(`LITERAL_PATH_DRIFT`) normally carries a replacement written in the author's
|
|
595
|
+
own form (alias stays alias, relative is recomputed relative, a path with no
|
|
596
|
+
include-root prefix keeps its coordinate space); the fix is one-directional
|
|
597
|
+
and `--write` applies it. Exit 1 while anchored drift remains. Three things
|
|
598
|
+
must hold before a replacement is offered at all: a rename explains the
|
|
599
|
+
reference, the destination itself resolves (otherwise the "fix" only moves the
|
|
600
|
+
drift), and the destination is path-shaped — a git path is raw bytes, and a
|
|
601
|
+
destination containing a quote or a newline would edit the program rather than
|
|
602
|
+
repair a reference. A finding that clears the first two but whose destination
|
|
603
|
+
leaves its own alias root is reported with the target only and marked *rewrite
|
|
604
|
+
by hand*; `--write` never touches it, so the summary counts writable
|
|
605
|
+
replacements separately.
|
|
606
|
+
- **Unanchored** (`--all`) — a literal that looks like a repo path and does not
|
|
607
|
+
resolve, with nothing to say where it went (`LITERAL_PATH_UNRESOLVED`).
|
|
608
|
+
Advisory: never written, never fails a run. It is opt-in because ArkGate
|
|
609
|
+
cannot tell a dead reference from an illustrative one, and reporting the
|
|
610
|
+
difference as if it could would be our limitation stated as a fact about your
|
|
611
|
+
code. The **count is always printed**, listed or not.
|
|
612
|
+
|
|
613
|
+
Three exit codes, so a pipeline can tell the three outcomes apart from the
|
|
614
|
+
status alone:
|
|
615
|
+
|
|
616
|
+
| exit | meaning |
|
|
617
|
+
| --- | --- |
|
|
618
|
+
| `0` | anchored mode ran and nothing is left |
|
|
619
|
+
| `1` | anchored drift remains |
|
|
620
|
+
| `2` | anchored mode could not run (no usable base ref) — this run proved nothing |
|
|
621
|
+
|
|
622
|
+
A green tick is printed only for `0`. With no usable base ref the run prints
|
|
623
|
+
`○ Anchored mode did not run` and exits `2`: a tick, or a zero status, over a
|
|
624
|
+
check that never happened is the false green this pass exists to remove.
|
|
625
|
+
|
|
626
|
+
`--write` refuses rather than risks the file, and every refusal is named in the
|
|
627
|
+
output: a symlinked leaf or parent (`symlink`), a hard link to a file the repo
|
|
628
|
+
does not own (`hard-link`), content that is not valid UTF-8 (`not-utf8` — a
|
|
629
|
+
whole-file rewrite would replace the offending byte with U+FFFD), a token that
|
|
630
|
+
has moved since the scan (`token-moved`), and anything resolving outside the
|
|
631
|
+
root (`outside-root`). The read-modify-write goes through a single
|
|
632
|
+
`O_NOFOLLOW` descriptor, so the path is never resolved twice.
|
|
633
|
+
|
|
634
|
+
The rename set is taken against the working tree, so a rename that is staged
|
|
635
|
+
but not yet committed is covered — the moment the drift is cheapest to fix. (A
|
|
636
|
+
bare `mv` without `git add` is invisible to rename detection: its destination is
|
|
637
|
+
untracked.) Without a usable base ref the
|
|
638
|
+
run says so instead of printing a green.
|
|
639
|
+
|
|
640
|
+
The pass reads the contract for one thing only — `include`, to learn which
|
|
641
|
+
prefixes a path may be written under — and ignores `exclude`: a contract must not
|
|
642
|
+
be able to hide drift from the pass that reports it, and a contract too broken to
|
|
643
|
+
parse is no reason to stop looking either. Scope: every text format where a repo
|
|
644
|
+
path is written by hand (`.ts .tsx .mts
|
|
645
|
+
.cts .js .jsx .mjs .cjs .css .scss .json .md`) — deliberately wider than the
|
|
646
|
+
TS/TSX gate the type-aware passes use, because a comment is not code and the
|
|
647
|
+
class was first found in a `.css` file. Generated files are skipped, and every
|
|
648
|
+
file the walk refuses is counted by reason in the output.
|
|
649
|
+
|
|
472
650
|
### Presets
|
|
473
651
|
|
|
474
652
|
- `hexagonal` / `layered` / `feature-sliced` / `monorepo` / **`ui-surface`** (UI/Vite/Remotion-style) / **`vertical-slice`** (features/* + peerIsolation) / **`ddd-bounded-contexts`** (contexts/*/domain|application|infra + shared kernel)
|
|
@@ -631,7 +809,7 @@ npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok,antigra
|
|
|
631
809
|
| Cursor | `.cursor/mcp.json` + `.cursor/rules/ark.mdc` | **Repo:** `.agents/skills/<name>/SKILL.md` (same catalog as Codex). Do not also copy into `.cursor/commands/` or `$CODEX_HOME/skills` — Cursor lists every path it scans. |
|
|
632
810
|
| OpenAI Codex | `.codex/config.toml` (project primary, relative `--root .`; configured on disk is not runtime-active until restart + `ark_identity` match); optional legacy `$CODEX_HOME/config.toml` fallback uses absolute roots and scoped secondaries — see [ai-gates.md](ai-gates.md) | **Repo:** `.agents/skills/<name>/SKILL.md`; **home:** `$CODEX_HOME/skills/<name>/SKILL.md` (`--codex-home`) |
|
|
633
811
|
| **Grok Build** | `.grok/hooks/ark-write-gate.json` + `.grok/config.toml` / `.mcp.json` | **Repo:** `.grok/skills/<name>/SKILL.md`; **home:** `$GROK_HOME/skills` (default `~/.grok/skills`, `--grok-home`) |
|
|
634
|
-
| Google Antigravity | `.agents/hooks.json` + `.agents/mcp_config.json` (+ `GEMINI.md` for shared Gemini consumers) | `.agents/skills/<name>/SKILL.md` |
|
|
812
|
+
| Google Antigravity | `.agents/hooks.json` + `.agents/mcp_config.json` (+ `GEMINI.md` for shared Gemini consumers) | **Repo:** `.agents/skills/<name>/SKILL.md`; **home:** `$ANTIGRAVITY_HOME/skills` (default `~/.gemini/config/skills`, `--antigravity-home`) |
|
|
635
813
|
| OpenCode | `opencode.json` MCP (`type: local`; advisory) | `.opencode/skills/<name>/SKILL.md` |
|
|
636
814
|
|
|
637
815
|
This is a path reference, not a guarantee table. Full copy-paste setups:
|
|
@@ -639,12 +817,12 @@ This is a path reference, not a guarantee table. Full copy-paste setups:
|
|
|
639
817
|
[README](../README.md#other-skills-only-when-you-need-them).
|
|
640
818
|
When several repositories share one machine, repo catalogs stay pinned and isolated; unchanged
|
|
641
819
|
skill bodies are not rewritten for a version stamp. Shared **home** catalogs (Codex since 4.2;
|
|
642
|
-
Claude/Grok since 4.6) are the machine floor: always latest additive, never downgrade. Refresh
|
|
643
|
-
with `--agent-homes` (or `--claude-home` / `--grok-home` / `--codex-home`). Absent home trees
|
|
820
|
+
Claude/Grok since 4.6; Antigravity since 4.8.5) are the machine floor: always latest additive, never downgrade. Refresh
|
|
821
|
+
with `--agent-homes` (or `--claude-home` / `--grok-home` / `--antigravity-home` / `--codex-home`). Absent home trees
|
|
644
822
|
are normal — doctor stays quiet until `ark-*` skills exist there. Pre-4.2 binaries ignore Codex
|
|
645
823
|
home metadata and lock, so upgrade legacy repos before they write the optional Codex home
|
|
646
824
|
catalog. See [AI gates — Codex skill catalog](ai-gates.md#codex-skill-catalog-skillmd-not-flat-prompts)
|
|
647
|
-
and [shared Claude/Grok homes](ai-gates.md#shared-claude--grok-home-skills).
|
|
825
|
+
and [shared Claude/Grok/Antigravity homes](ai-gates.md#shared-claude--grok-home-skills).
|
|
648
826
|
|
|
649
827
|
### Install skills — Ark and ecosystem {#install-skills-ark-and-ecosystem}
|
|
650
828
|
|
|
@@ -899,6 +1077,10 @@ edges are not denied by that rule.
|
|
|
899
1077
|
- **Allowed:** same-slice imports when both paths classify; classic non-peerIsolation denies still apply across layers.
|
|
900
1078
|
- **`sliceFolders`:** optional parent segments (default: inferred from layer globs).
|
|
901
1079
|
- **Fail-closed:** missing paths, empty/unresolvable slice folders, or unclassifiable either side → **deny** via peerIsolation (cannot prove same-slice).
|
|
1080
|
+
- **`sharedRoots`** (4.8.4): roots the repo declares shared on purpose (`["ui", "hooks", "lib/permissions"]`). A file under a declared shared root is evidence, not an unclassifiable path, so fail-closed stops firing on every shared file. **Anchored** — the root starts the path, optionally after one `src/` or `app/`; write deeper or monorepo roots out (`packages/web/src/ui`) or glob them, and a bare `*` / `**` is refused. A path that still resolves to a slice keeps its slice.
|
|
1081
|
+
- **`allowedCrossSlice`** (4.8.4): `[{ "from": "features/checkout", "to": "features/catalog" }]` — one directed slice→slice edge the repo declares on purpose. The reverse still denies.
|
|
1082
|
+
- **The denial names its reason:** `cross-slice edge a → b` (a fact about the code) vs `unclassifiable path (…)`, `no slice folders`, `no path evidence` (facts about the evidence ArkGate had).
|
|
1083
|
+
- Promoting a genuinely shared slice to its own layer remains the recommended model; the two declarations exist so ArkGate can enforce a repo that deliberately chose otherwise.
|
|
902
1084
|
- Enforced by `ark-check`, `arkgate/eslint`, and `ark-mcp` (path-aware edges and path-less intent refs share the same SoT).
|
|
903
1085
|
- Fixes are **judgment** (not mechanical-safe).
|
|
904
1086
|
|
package/docs/ai-gates.md
CHANGED
|
@@ -465,7 +465,7 @@ severity **info**, marked `deferred: true`, and omitted from doctor **Primary ne
|
|
|
465
465
|
`/ark-upgrade` on Grok/Claude is not Incomplete because of them. **Temp/upgrade primary roots**
|
|
466
466
|
stay fail-closed urgent (rewritten, not multi-project).
|
|
467
467
|
|
|
468
|
-
### Shared Claude / Grok home skills {#shared-claude--grok-home-skills}
|
|
468
|
+
### Shared Claude / Grok / Antigravity home skills {#shared-claude--grok-home-skills}
|
|
469
469
|
|
|
470
470
|
Project catalogs follow that checkout’s ArkGate pin (they may lag). Shared user-home catalogs
|
|
471
471
|
are the **machine floor**:
|
|
@@ -474,11 +474,19 @@ are the **machine floor**:
|
|
|
474
474
|
|-------|------|------|
|
|
475
475
|
| Claude home | `$CLAUDE_HOME/skills` (default `~/.claude/skills`) | `--claude-home` |
|
|
476
476
|
| Grok home | `$GROK_HOME/skills` (default `~/.grok/skills`) | `--grok-home` |
|
|
477
|
-
|
|
|
477
|
+
| Antigravity home | `$ANTIGRAVITY_HOME/skills` (default `~/.gemini/config/skills`) | `--antigravity-home` |
|
|
478
|
+
| All four + Codex | same monotonic protocol | `--agent-homes` |
|
|
479
|
+
|
|
480
|
+
Antigravity’s official global catalog is `~/.gemini/config/skills` (workspace catalog remains
|
|
481
|
+
`.agents/skills`). Claude/Grok home copies override or duplicate the project catalog in the same
|
|
482
|
+
session, so `--agent-homes` skips those homes when `.agents/skills` already exists. The Antigravity
|
|
483
|
+
global catalog is the machine floor for **every** workspace, so `--antigravity-home` still writes
|
|
484
|
+
it. `--prune-home-duplicates` does **not** delete `~/.gemini/config/skills/ark-*`.
|
|
478
485
|
|
|
479
486
|
Doctor reports `agentHomeGaps` only when those catalogs already contain `ark-*` skills and
|
|
480
487
|
lag the installed package. Temp/upgrade `--root` never mutates default user homes. Cursor
|
|
481
488
|
sessions treat a stale Claude home as urgent because Cursor loads `~/.claude/skills`.
|
|
489
|
+
Antigravity sessions treat a stale `~/.gemini/config/skills` catalog as urgent.
|
|
482
490
|
|
|
483
491
|
```bash
|
|
484
492
|
npx arkgate-check --install-agent-gates --skills-only --agent-homes --force
|
|
@@ -589,6 +597,8 @@ Install:
|
|
|
589
597
|
npx ark-check --install-agent-gates --tools antigravity
|
|
590
598
|
# alias:
|
|
591
599
|
npx ark-check --install-agent-gates --tools agy
|
|
600
|
+
# refresh the official global catalog (all workspaces):
|
|
601
|
+
npx ark-check --install-agent-gates --skills-only --antigravity-home --force
|
|
592
602
|
```
|
|
593
603
|
|
|
594
604
|
| File | Role |
|
|
@@ -597,6 +607,7 @@ npx ark-check --install-agent-gates --tools agy
|
|
|
597
607
|
| `.agents/mcp_config.json` | Official workspace MCP (`mcpServers.ark` stdio) |
|
|
598
608
|
| `GEMINI.md` | Instruction rule for Gemini CLI / legacy consumers sharing the tree |
|
|
599
609
|
| `.agents/skills/*/SKILL.md` | Agent Skills catalog (shared path with Codex) |
|
|
610
|
+
| `~/.gemini/config/skills/*/SKILL.md` | Official Antigravity **global** catalog (`--antigravity-home` / `--agent-homes`) |
|
|
600
611
|
| `AGENTS.md` + `.mcp.json` + CI | Shared with other hosts (`.mcp.json` is not the Antigravity MCP path) |
|
|
601
612
|
|
|
602
613
|
**Write tools covered:** `write_to_file`, `replace_file_content`, `multi_replace_file_content`.
|
package/docs/arkorder.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# ArkOrder
|
|
2
|
+
|
|
3
|
+
**Write. Check. Ship.** Layers can be green while an agent still PATCHes the
|
|
4
|
+
billing plan as if it were a seat count. ArkOrder is the extra that names the
|
|
5
|
+
few slow product decisions and stops that write.
|
|
6
|
+
|
|
7
|
+
Import: `arkgate/order` (same npm package `arkgate`). Off until you add
|
|
8
|
+
`arkOrder` on schema `1.3`. Absence is silent. In-memory. Not durable. It is
|
|
9
|
+
a library plus sensors, not a service. Does **not** replace ArkRun.
|
|
10
|
+
|
|
11
|
+
First-contact copy: freeze / four verbs / no `update`. Haken (ξ vs s) lives
|
|
12
|
+
below.
|
|
13
|
+
|
|
14
|
+
Canonical plan seed: [plans/arkorder/README.md](plans/arkorder/README.md).
|
|
15
|
+
ADRs: [0027](adr/0027-arkorder-gated-extra-plane.md)–[0030](adr/0030-opt-in-extras-same-npm-package.md),
|
|
16
|
+
[0033](adr/0033-arkorder-runtime-half-is-arkrun.md) (runtime half is ArkRun).
|
|
17
|
+
Config: [configuration.md](configuration.md). Surface:
|
|
18
|
+
[package-surface.md](package-surface.md#experimental-opt-in-surfaces).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## What it is (and is not)
|
|
23
|
+
|
|
24
|
+
| Is | Is not |
|
|
25
|
+
|----|--------|
|
|
26
|
+
| A **library** (`createOrderPlane`) plus **static sensors** | A running service, daemon, or hosted plane |
|
|
27
|
+
| Four verbs: `release` / `project` / `ingest` / `proposeRelease` | A generic `update` / `patch` / `set` |
|
|
28
|
+
| Opt-in extra on `ark.config.json` | Always-on; compact starters leave it off |
|
|
29
|
+
| Consumer-named slow keys (`xiKeys`) | A construction OS, BIM, or FirmPack |
|
|
30
|
+
| Same npm tarball | not `@arkgate/order` |
|
|
31
|
+
|
|
32
|
+
If the extra is off, every ArkOrder sensor is silent. If it is on, the same
|
|
33
|
+
write gate / CI / ESLint envelope as Layers applies. Domain stays plane-free:
|
|
34
|
+
`createOrderPlane` lives in `arkOrder.planeRoots`.
|
|
35
|
+
|
|
36
|
+
ArkRun is **how the app talks** (intents, transport, information package).
|
|
37
|
+
ArkOrder is **what the app may treat as pattern**. Two extras. One activation
|
|
38
|
+
shape (`mode` + `managedLayers`). Roots keep different names because they
|
|
39
|
+
point at different factories: `arkRun.kernelRoots` vs `arkOrder.planeRoots`.
|
|
40
|
+
`compositionRoots` remains an alias of `kernelRoots`. See
|
|
41
|
+
[activation](#activation-same-shape-as-arkrun).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Already shipped (named APIs)
|
|
46
|
+
|
|
47
|
+
Adopters kept redesigning this extra because the names were not on one page.
|
|
48
|
+
They already exist:
|
|
49
|
+
|
|
50
|
+
| Ask | API | Since |
|
|
51
|
+
|-----|-----|-------|
|
|
52
|
+
| Escalation as a first-class concept | `IngestResult = IngestAbsorb \| IngestEscalate` (`kind`, `reason`) | 4.8.0 |
|
|
53
|
+
| Projection at the boundary | `Projector = (release, sigma) => Projection` | 4.8.0 |
|
|
54
|
+
| Cap on badly designed slow parameters | `DEFAULT_MAX_XI_KEYS = 7`, `maxXiKeys`, `ARKORDER_TOO_MANY_PARAMS`, `ARKORDER_EMPTY_XI`, `ARKORDER_NESTED_XI` | 4.8.0 |
|
|
55
|
+
| Valved proposals, never direct mutation | `ProposeResult { nextXi, blastRadius, invalidations }` | 4.8.0 |
|
|
56
|
+
| Typed cell schema | `XiSchema` / `XiPropertySchema` | 4.8.0 |
|
|
57
|
+
| Named slow keys on the write path | `arkOrder.xiKeys`; `ARKORDER_XI_FIELD_WRITE` | 4.8.3 |
|
|
58
|
+
| Factory isolation | `createOrderPlane` from `arkgate/order` only | 4.8.0 |
|
|
59
|
+
| Information budget | `informationBudget.cannotObserve`; `ARKORDER_INFORMATION_BUDGET` | 4.8.5 |
|
|
60
|
+
| σ freshness, never ξ | `sigmaMaxAgeMs` / `σ.freshUntil`; `ARKORDER_XI_TTL`, `ARKORDER_STALE_SIGMA` | 4.8.5 |
|
|
61
|
+
| Escalate to a person | `IngestEscalate.target` including `human` | 4.8.5 |
|
|
62
|
+
| Shadow / replay / compare | ArkRun `shadowInformationPackage` / `compareInformationPackages` / `replayInformationPackages` | 4.8.5 |
|
|
63
|
+
|
|
64
|
+
Nothing here is a hosted runtime. Nothing here can be “down”. A degraded-mode
|
|
65
|
+
contract would defend against an outage that cannot happen.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Four verbs
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { createOrderPlane } from 'arkgate/order';
|
|
73
|
+
|
|
74
|
+
const plane = createOrderPlane({
|
|
75
|
+
projector, // consumer: (release, sigma) => { allowedKinds, invalidated }
|
|
76
|
+
xiSchema, // JSON Schema object; additionalProperties false
|
|
77
|
+
maxXiKeys, // default 7
|
|
78
|
+
clocks, // injected; Domain must not call Date.now
|
|
79
|
+
packs, // data, not user predicates
|
|
80
|
+
informationBudget, // optional { cannotObserve: ['ledger'] } — not a config key
|
|
81
|
+
sigmaMaxAgeMs, // optional σ freshness; never on ξ — not a config key
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
plane.release(xi, sigma); // freeze, version, hash. No in-place mutate
|
|
85
|
+
plane.project(); // derive allowed s + invalidations
|
|
86
|
+
plane.ingest(event); // absorb or escalate. Never returns a Release
|
|
87
|
+
plane.proposeRelease(delta); // blast radius. Empty blast = domain error
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
There is no `update()`. Calling `update` / `patch` / `set` on the plane throws
|
|
91
|
+
`ARKORDER_FORBIDDEN_METHOD` and, on the write path, emits
|
|
92
|
+
`ARKORDER_GENERIC_UPDATE`.
|
|
93
|
+
|
|
94
|
+
| Field write | Verb |
|
|
95
|
+
|-------------|------|
|
|
96
|
+
| Invoice, seat within cap, timesheet, daily log | `ingest` → absorb |
|
|
97
|
+
| Over cap / invariant pressure | `ingest` → escalate |
|
|
98
|
+
| Change plan / protocol / cost-code bound | `proposeRelease` then `release` |
|
|
99
|
+
| PATCH the slow key through Prisma/Drizzle | `ARKORDER_XI_FIELD_WRITE` |
|
|
100
|
+
|
|
101
|
+
Copy [examples/arkorder-billing/](../examples/arkorder-billing/) and rename the
|
|
102
|
+
three keys. Membership ids (`projectId`) are not keys: a `proposeRelease` that
|
|
103
|
+
does not change `h(ξ)` fails closed (`ARKORDER_EMPTY_BLAST`).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Config
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"schemaVersion": "1.3",
|
|
112
|
+
"arkOrder": {
|
|
113
|
+
"mode": "advisory",
|
|
114
|
+
"planeRoots": ["src/composition/order-plane.ts"],
|
|
115
|
+
"managedLayers": ["Application"],
|
|
116
|
+
"maxXiKeys": 7,
|
|
117
|
+
"xiKeys": ["plan", "cycle", "tenancy"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| Field | Meaning |
|
|
123
|
+
|-------|---------|
|
|
124
|
+
| `mode` | `advisory` (default) or `enforced`. Same word as ArkRun / ArkRules |
|
|
125
|
+
| `managedLayers` | Layers whose persistence writes of `xiKeys` are the skip |
|
|
126
|
+
| `planeRoots` | Files allowed to call `createOrderPlane` |
|
|
127
|
+
| `maxXiKeys` | Cap on ξ (default 7). Haken: few slow modes |
|
|
128
|
+
| `xiKeys` | Optional 3–5 slow names. Empty → `ARKORDER_XI_FIELD_WRITE` silent |
|
|
129
|
+
|
|
130
|
+
Unknown keys fail closed. Empty `planeRoots` in `enforced` fails
|
|
131
|
+
`ARKORDER_MISSING_PLANE`. Demotion or deletion is a policy-delta **weakening**.
|
|
132
|
+
This library’s 4-layer authoring contract does **not** turn the extra on.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Activation (same shape as ArkRun)
|
|
137
|
+
|
|
138
|
+
Both extras already share **`mode`** and **`managedLayers`**. They diverge on
|
|
139
|
+
one axis: the factory root.
|
|
140
|
+
|
|
141
|
+
| | ArkOrder | ArkRun |
|
|
142
|
+
|--|----------|--------|
|
|
143
|
+
| Extra key | `arkOrder` | `arkRun` |
|
|
144
|
+
| Schema | `1.3+` | `1.2+` |
|
|
145
|
+
| Factory | `createOrderPlane` from `arkgate/order` | `createStrictArkKernel` from `arkgate/runtime` |
|
|
146
|
+
| Roots | `planeRoots` | `kernelRoots` (`compositionRoots` alias) |
|
|
147
|
+
| Silence | absence of the extra | absence of the extra |
|
|
148
|
+
|
|
149
|
+
Do not rename `planeRoots` to `kernelRoots`. They name different factories.
|
|
150
|
+
List both on `ark-check --sensors` (same table, same tier vocabulary).
|
|
151
|
+
|
|
152
|
+
Turn extras on with `/ark-adopt`. Place new files with `/ark-place`. There is
|
|
153
|
+
no `/ark-order` skill.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Sensors (closed)
|
|
158
|
+
|
|
159
|
+
Direct evidence blocks. Inference never does. Default advisory; promotable
|
|
160
|
+
except withdrawn heuristics.
|
|
161
|
+
|
|
162
|
+
| Diagnostic | Skip |
|
|
163
|
+
|------------|------|
|
|
164
|
+
| `ARKORDER_MISSING_PLANE` | Extra on, no `createOrderPlane` in `planeRoots` |
|
|
165
|
+
| `ARKORDER_KERNEL_IN_DOMAIN` | Domain-role layer imports `arkgate/order` |
|
|
166
|
+
| `ARKORDER_GENERIC_UPDATE` | `update` / `patch` / `set` on the plane |
|
|
167
|
+
| `ARKORDER_TOO_MANY_PARAMS` | ξ keys > `maxXiKeys` |
|
|
168
|
+
| `ARKORDER_INGEST_WRITES_XI` | `ingest` result assigned into a Release / ξ store |
|
|
169
|
+
| `ARKORDER_XI_FIELD_WRITE` | Managed-layer driver import **and** write token **and** a declared `xiKeys` name |
|
|
170
|
+
| `ARKORDER_INFORMATION_BUDGET` | `h(ξ)` allows a kind in `informationBudget.cannotObserve` |
|
|
171
|
+
| `ARKORDER_XI_TTL` | ξ named ttl/freshUntil/maxAge — freshness is σ |
|
|
172
|
+
| `ARKORDER_STALE_SIGMA` | ingest after σ.freshUntil, or after `release.releasedAt` + `sigmaMaxAgeMs` |
|
|
173
|
+
|
|
174
|
+
Why / fix: [diagnostics.md](diagnostics.md#ARKORDER_MISSING_PLANE).
|
|
175
|
+
`ark-check --sensors` lists every extra sensor with plane, tier, and whether
|
|
176
|
+
it can ever be enforced.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Runtime half
|
|
181
|
+
|
|
182
|
+
Shadow, replay, provenance, and compare belong to **ArkRun** (information
|
|
183
|
+
package, inspector, in-memory compare). ArkOrder does not grow a bus, outbox,
|
|
184
|
+
or hosted replay. [ADR 0033](adr/0033-arkorder-runtime-half-is-arkrun.md).
|
|
185
|
+
|
|
186
|
+
Durability (`K01`) stays parked. In-memory is the honesty line.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## What we will not build here
|
|
191
|
+
|
|
192
|
+
- another event bus
|
|
193
|
+
- a general workflow engine
|
|
194
|
+
- a permissions engine
|
|
195
|
+
- a central store holding operational state
|
|
196
|
+
- a DSL that duplicates domain / DB / ArkRules
|
|
197
|
+
- a coordinator required on every request
|
|
198
|
+
- a degraded-mode contract (nothing can be down)
|
|
199
|
+
|
|
200
|
+
If a “slow parameter” changes with every click, it is not an order parameter.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Next step
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npx arkgate-check --doctor
|
|
208
|
+
# copy examples/arkorder-billing/ and rename the three keys
|
|
209
|
+
# /ark-adopt to turn arkOrder on advisory
|
|
210
|
+
```
|