@telora/daemon 0.22.181 → 0.22.187
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/build-info.json +9 -3
- package/dist/audit/audit-floor-policy.d.ts +188 -0
- package/dist/audit/audit-floor-policy.d.ts.map +1 -0
- package/dist/audit/audit-floor-policy.js +353 -0
- package/dist/audit/audit-floor-policy.js.map +1 -0
- package/dist/audit/audit-prompt.d.ts +4 -177
- package/dist/audit/audit-prompt.d.ts.map +1 -1
- package/dist/audit/audit-prompt.js +6 -329
- package/dist/audit/audit-prompt.js.map +1 -1
- package/dist/completion/escalations.d.ts.map +1 -1
- package/dist/completion/escalations.js +3 -1
- package/dist/completion/escalations.js.map +1 -1
- package/dist/focus/focus-executor.d.ts.map +1 -1
- package/dist/focus/focus-executor.js +2 -0
- package/dist/focus/focus-executor.js.map +1 -1
- package/dist/focus/session-health.d.ts.map +1 -1
- package/dist/focus/session-health.js +2 -1
- package/dist/focus/session-health.js.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.d.ts +52 -17
- package/dist/focus-stage-lifecycle/planning-release.d.ts.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.js +58 -70
- package/dist/focus-stage-lifecycle/planning-release.js.map +1 -1
- package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts +108 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts.map +1 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.js +174 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.js.map +1 -0
- package/dist/git/merge-to-main.d.ts.map +1 -1
- package/dist/git/merge-to-main.js.map +1 -1
- package/dist/nexus/index.d.ts.map +1 -1
- package/dist/nexus/index.js +2 -1
- package/dist/nexus/index.js.map +1 -1
- package/dist/nexus/intake-prompt-sections.d.ts +70 -0
- package/dist/nexus/intake-prompt-sections.d.ts.map +1 -0
- package/dist/nexus/intake-prompt-sections.js +145 -0
- package/dist/nexus/intake-prompt-sections.js.map +1 -0
- package/dist/nexus/intake-spawn.d.ts +49 -13
- package/dist/nexus/intake-spawn.d.ts.map +1 -1
- package/dist/nexus/intake-spawn.js +45 -122
- package/dist/nexus/intake-spawn.js.map +1 -1
- package/dist/nexus/intake.d.ts +55 -0
- package/dist/nexus/intake.d.ts.map +1 -1
- package/dist/nexus/intake.js +62 -1
- package/dist/nexus/intake.js.map +1 -1
- package/dist/prd/arm-readiness.d.ts +93 -0
- package/dist/prd/arm-readiness.d.ts.map +1 -0
- package/dist/prd/arm-readiness.js +254 -0
- package/dist/prd/arm-readiness.js.map +1 -0
- package/dist/prd/arm-refusal.d.ts +149 -0
- package/dist/prd/arm-refusal.d.ts.map +1 -0
- package/dist/prd/arm-refusal.js +219 -0
- package/dist/prd/arm-refusal.js.map +1 -0
- package/dist/prd/controller-shared.d.ts +111 -0
- package/dist/prd/controller-shared.d.ts.map +1 -1
- package/dist/prd/controller-shared.js +3 -1
- package/dist/prd/controller-shared.js.map +1 -1
- package/dist/prd/controller.d.ts +16 -10
- package/dist/prd/controller.d.ts.map +1 -1
- package/dist/prd/controller.js +28 -35
- package/dist/prd/controller.js.map +1 -1
- package/dist/prd/frontier-arming.d.ts +151 -0
- package/dist/prd/frontier-arming.d.ts.map +1 -0
- package/dist/prd/frontier-arming.js +315 -0
- package/dist/prd/frontier-arming.js.map +1 -0
- package/dist/prd/index.d.ts +10 -1
- package/dist/prd/index.d.ts.map +1 -1
- package/dist/prd/index.js +9 -1
- package/dist/prd/index.js.map +1 -1
- package/dist/prd/scoping-prompt.d.ts +68 -0
- package/dist/prd/scoping-prompt.d.ts.map +1 -0
- package/dist/prd/scoping-prompt.js +86 -0
- package/dist/prd/scoping-prompt.js.map +1 -0
- package/dist/prompt/prompt-contradictions.d.ts +20 -1
- package/dist/prompt/prompt-contradictions.d.ts.map +1 -1
- package/dist/prompt/prompt-contradictions.js +35 -0
- package/dist/prompt/prompt-contradictions.js.map +1 -1
- package/dist/prompt/team-prompt-base.d.ts +18 -0
- package/dist/prompt/team-prompt-base.d.ts.map +1 -1
- package/dist/prompt/team-prompt-base.js +56 -11
- package/dist/prompt/team-prompt-base.js.map +1 -1
- package/dist/prompt-sections/persona-sections.d.ts +36 -13
- package/dist/prompt-sections/persona-sections.d.ts.map +1 -1
- package/dist/prompt-sections/persona-sections.js +93 -16
- package/dist/prompt-sections/persona-sections.js.map +1 -1
- package/dist/prompt-sections/scoping-sections.d.ts +19 -5
- package/dist/prompt-sections/scoping-sections.d.ts.map +1 -1
- package/dist/prompt-sections/scoping-sections.js +45 -38
- package/dist/prompt-sections/scoping-sections.js.map +1 -1
- package/dist/prompt-sections/shared.d.ts +8 -0
- package/dist/prompt-sections/shared.d.ts.map +1 -1
- package/dist/prompt-sections/shared.js.map +1 -1
- package/dist/queries/focus-criteria-standing.d.ts +170 -7
- package/dist/queries/focus-criteria-standing.d.ts.map +1 -1
- package/dist/queries/focus-criteria-standing.js +143 -8
- package/dist/queries/focus-criteria-standing.js.map +1 -1
- package/dist/queries/focus-ratify-release.d.ts +43 -0
- package/dist/queries/focus-ratify-release.d.ts.map +1 -0
- package/dist/queries/focus-ratify-release.js +45 -0
- package/dist/queries/focus-ratify-release.js.map +1 -0
- package/dist/queries/focuses.d.ts +0 -10
- package/dist/queries/focuses.d.ts.map +1 -1
- package/dist/queries/focuses.js +0 -14
- package/dist/queries/focuses.js.map +1 -1
- package/dist/queries/prd.d.ts +31 -0
- package/dist/queries/prd.d.ts.map +1 -1
- package/dist/queries/prd.js +26 -1
- package/dist/queries/prd.js.map +1 -1
- package/dist/queries/shared.js +1 -1
- package/dist/resolvers/focus-criteria-standing.d.ts.map +1 -1
- package/dist/resolvers/focus-criteria-standing.js +324 -25
- package/dist/resolvers/focus-criteria-standing.js.map +1 -1
- package/dist/security/security-auto-inject.d.ts +51 -0
- package/dist/security/security-auto-inject.d.ts.map +1 -1
- package/dist/security/security-auto-inject.js +101 -11
- package/dist/security/security-auto-inject.js.map +1 -1
- package/dist/security/security-scan-engine.d.ts +4 -4
- package/dist/security/security-scan-engine.d.ts.map +1 -1
- package/dist/security/security-scan-engine.js +6 -0
- package/dist/security/security-scan-engine.js.map +1 -1
- package/dist/session/session-lineage.d.ts.map +1 -1
- package/dist/session/session-lineage.js +2 -0
- package/dist/session/session-lineage.js.map +1 -1
- package/dist/shell/constants.d.ts +5 -0
- package/dist/shell/constants.d.ts.map +1 -1
- package/dist/shell/constants.js +5 -0
- package/dist/shell/constants.js.map +1 -1
- package/dist/shell/daemon-instance.d.ts +74 -64
- package/dist/shell/daemon-instance.d.ts.map +1 -1
- package/dist/shell/daemon-instance.js +16 -121
- package/dist/shell/daemon-instance.js.map +1 -1
- package/dist/shell/health-events.js +1 -1
- package/dist/shell/health-events.js.map +1 -1
- package/dist/shell/instance-liveness.d.ts +112 -0
- package/dist/shell/instance-liveness.d.ts.map +1 -0
- package/dist/shell/instance-liveness.js +205 -0
- package/dist/shell/instance-liveness.js.map +1 -0
- package/dist/shell/schema-version-gate.d.ts +22 -0
- package/dist/shell/schema-version-gate.d.ts.map +1 -1
- package/dist/shell/schema-version-gate.js +116 -6
- package/dist/shell/schema-version-gate.js.map +1 -1
- package/dist/shell/worker-pidfile.d.ts +21 -8
- package/dist/shell/worker-pidfile.d.ts.map +1 -1
- package/dist/shell/worker-pidfile.js +38 -9
- package/dist/shell/worker-pidfile.js.map +1 -1
- package/dist/spawn/lead-launch.d.ts.map +1 -1
- package/dist/spawn/lead-launch.js +2 -1
- package/dist/spawn/lead-launch.js.map +1 -1
- package/dist/spawn/one-shot-scoping-spawn.d.ts +51 -0
- package/dist/spawn/one-shot-scoping-spawn.d.ts.map +1 -0
- package/dist/spawn/one-shot-scoping-spawn.js +156 -0
- package/dist/spawn/one-shot-scoping-spawn.js.map +1 -0
- package/dist/spawn/process-spawn.d.ts +12 -0
- package/dist/spawn/process-spawn.d.ts.map +1 -1
- package/dist/spawn/process-spawn.js +1 -1
- package/dist/spawn/process-spawn.js.map +1 -1
- package/dist/spawn/prompt-assembly.d.ts +8 -0
- package/dist/spawn/prompt-assembly.d.ts.map +1 -1
- package/dist/spawn/prompt-assembly.js +15 -3
- package/dist/spawn/prompt-assembly.js.map +1 -1
- package/dist/spawn/worktree-session.d.ts +24 -6
- package/dist/spawn/worktree-session.d.ts.map +1 -1
- package/dist/spawn/worktree-session.js +37 -14
- package/dist/spawn/worktree-session.js.map +1 -1
- package/dist/testing/arm-coverage-model.d.ts +75 -0
- package/dist/testing/arm-coverage-model.d.ts.map +1 -0
- package/dist/testing/arm-coverage-model.js +114 -0
- package/dist/testing/arm-coverage-model.js.map +1 -0
- package/dist/testing/fixtures/index.js +1 -1
- package/dist/types/index.js +1 -1
- package/dist/verify/verification-boundary-env.d.ts +7 -2
- package/dist/verify/verification-boundary-env.d.ts.map +1 -1
- package/dist/verify/verification-boundary-env.js +9 -4
- package/dist/verify/verification-boundary-env.js.map +1 -1
- package/package.json +2 -2
package/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commitSha": "
|
|
3
|
-
"builtAt": "2026-09-
|
|
2
|
+
"commitSha": "db7b06909",
|
|
3
|
+
"builtAt": "2026-09-23T12:14:56.419Z",
|
|
4
4
|
"expectedMigrations": [
|
|
5
5
|
"20250829113330_create_org_nodes_table.sql",
|
|
6
6
|
"20250829113402_fix_function_security_search_path.sql",
|
|
@@ -819,6 +819,12 @@
|
|
|
819
819
|
"20260920213405_arm_covered_targets_are_fixed_at_the_arm.sql",
|
|
820
820
|
"20260920220952_playbooks_organization_id_nullable.sql",
|
|
821
821
|
"20260920225339_builtin_workflow_child_policies_authorize_on_entity.sql",
|
|
822
|
-
"20260921000043_stamp_arm_covered_target_nodes.sql"
|
|
822
|
+
"20260921000043_stamp_arm_covered_target_nodes.sql",
|
|
823
|
+
"20260922150418_product_request_source_and_mirrored_nodes.sql",
|
|
824
|
+
"20260922173056_arm_states_the_future_it_covers.sql",
|
|
825
|
+
"20260922185904_focus_debug_arm_refused_section.sql",
|
|
826
|
+
"20260922221935_product_request_observation_snapshot.sql",
|
|
827
|
+
"20260922225316_product_request_observation_entry_is_atomic.sql",
|
|
828
|
+
"20260923002532_capture_request_observation_in_one_snapshot.sql"
|
|
823
829
|
]
|
|
824
830
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AUDIT FLOOR: the round-5 pre-condition, as DATA.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `audit-prompt.ts` when that file crossed the daemon file-size
|
|
5
|
+
* gate. Nothing about the floor changed in the move: this module owns the
|
|
6
|
+
* policy structure, the closed lexicon its sentences are composed from, the
|
|
7
|
+
* backstop over its remaining prose, and the renderers; `audit-prompt.ts` owns
|
|
8
|
+
* the prompt that embeds the rendered section. The pin that guarantees the
|
|
9
|
+
* whole rendered section (`FLOOR_SECTION_PIN` in `audit-phase.test.ts`) is
|
|
10
|
+
* unmoved and unchanged, which is what makes this a MOVE rather than an edit.
|
|
11
|
+
*
|
|
12
|
+
* @module audit/audit-floor-policy
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Round-5 pre-condition: the focus's own declared floor.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately OUTSIDE the SHARED-AUDIT-GUIDE sentinels, for the same reason
|
|
18
|
+
* the residue hold below is: it states a precondition that only a pass holding
|
|
19
|
+
* the daemon's `focus.criteria_standing` section can satisfy, and the MCP
|
|
20
|
+
* guide's readers have no such section.
|
|
21
|
+
*
|
|
22
|
+
* WHY IT EXISTS. Round 5 anchors one remediation delivery per injection, and
|
|
23
|
+
* nothing in that loop ever asked what the focus SAID IT WAS FOR. An
|
|
24
|
+
* elaboration loop with no stated stopping condition does not stop -- it runs
|
|
25
|
+
* until someone gets tired -- so a focus grows deliveries while its declared
|
|
26
|
+
* criteria sit close to met. The standing section is the stated condition; this
|
|
27
|
+
* text is what makes the pass CONSULT it before it anchors, rather than after.
|
|
28
|
+
*
|
|
29
|
+
* The bases are given distinct instructions on purpose. The one that must not
|
|
30
|
+
* collapse into the others is `no_criteria_declared`: an empty criteria set is
|
|
31
|
+
* UNMEASURED, not arrived, and a pass that read it as a floor would stop
|
|
32
|
+
* hardest on exactly the focuses that declared nothing to be measured against.
|
|
33
|
+
*
|
|
34
|
+
* WHAT THE FLOOR IS NOT (round-5 correction, 2026-09-18). An earlier wording
|
|
35
|
+
* made CRITERION COVERAGE the test for whether a new root cause could be
|
|
36
|
+
* anchored, which converts the floor into the freeze the request rules out: a
|
|
37
|
+
* genuinely new root cause is perfectly capable of sitting inside an
|
|
38
|
+
* already-addressed criterion, and suppressing it there loses real signal to a
|
|
39
|
+
* bookkeeping fact about which criteria have deliveries pointing at them. The
|
|
40
|
+
* floor turns on RESIDUE (or restatement) vs GENUINELY NEW ROOT CAUSE, which
|
|
41
|
+
* is orthogonal to coverage: coverage answers "is there open declared work?",
|
|
42
|
+
* never "is this cause new?".
|
|
43
|
+
*
|
|
44
|
+
* WHY THE FLOOR IS DATA (rounds 6-7, 2026-09-19). Two earlier guards READ the
|
|
45
|
+
* hand-written floor prose looking for a restriction -- one sentence at a time,
|
|
46
|
+
* then across a wider window -- and both lost the same way: the restriction
|
|
47
|
+
* moved to a sentence the reading missed, or a wording its vocabulary lacked.
|
|
48
|
+
* So the normative content became the structure below, the prose became its
|
|
49
|
+
* rendering, and no rule carries a sentence of its own. The normative sentence
|
|
50
|
+
* is COMPOSED from the rule's typed fields against a CLOSED lexicon
|
|
51
|
+
* (`CANDIDATE_SUBJECT`, `DISPOSITION_VERB`, `UNCONDITIONAL_SCOPE`): subject
|
|
52
|
+
* from `candidate`, verb from `disposition`, scope from `conditions`, where an
|
|
53
|
+
* empty `conditions` renders an explicit "in every case this basis can present"
|
|
54
|
+
* rather than a silence a reader fills with the old freeze. Keep that: it makes
|
|
55
|
+
* a CONDITION countable instead of something to read prose for.
|
|
56
|
+
*
|
|
57
|
+
* WHY THE REMAINING PROSE IS PINNED BY EQUALITY (round-8 correction,
|
|
58
|
+
* 2026-09-19). Round 7 left the context prose -- leads, situations, caveats,
|
|
59
|
+
* obligations, and the two paragraphs `renderFloorSection` writes directly --
|
|
60
|
+
* guarded by `findFloorProseViolations`, and the commit that shipped it called
|
|
61
|
+
* that "a whitelist of CHANNEL, not an enumeration of wording". THAT CLAIM WAS
|
|
62
|
+
* FALSE, and review demonstrated it. `CANDIDATE_NOUN` and
|
|
63
|
+
* `DISPOSITION_VERB_IN_PROSE` are finite regex vocabularies, so the guard only
|
|
64
|
+
* recognised a normative claim written in words it already knew: appending
|
|
65
|
+
* "Fresh findings wait for review." or "A genuinely new root cause proceeds
|
|
66
|
+
* after every existing delivery is reviewed." draws NO violation and renders a
|
|
67
|
+
* contradictory restriction. Fourth iteration of one lesson, now unmistakable:
|
|
68
|
+
* ANY guard asking "does this text MEAN something normative?" loses, because
|
|
69
|
+
* meaning is open-ended.
|
|
70
|
+
*
|
|
71
|
+
* So the floor stops asking. This policy is a static constant, so the strings
|
|
72
|
+
* it can put in front of an assessor are a fixed, finite set, and the PRIMARY
|
|
73
|
+
* GUARANTEE is an equality pin on the whole rendered section:
|
|
74
|
+
* `FLOOR_SECTION_PIN` in audit-phase.test.ts holds an independent copy and the
|
|
75
|
+
* suite asserts `renderFloorSection()` equals it line for line. A synonym, an
|
|
76
|
+
* unlisted vocabulary and a wording nobody imagined then fail identically --
|
|
77
|
+
* not because a rule recognises them, but because none of them are the pinned
|
|
78
|
+
* string. It covers EVERY string the assessor reads here, the two paragraphs
|
|
79
|
+
* `renderFloorSection` writes among them, which no field-level guard ever saw.
|
|
80
|
+
*
|
|
81
|
+
* The cost is the intended one: editing floor prose is a TWO-PLACE, VISIBLE act
|
|
82
|
+
* -- the author updates the pin in the same change and a reviewer reads both
|
|
83
|
+
* halves. The pin is literal text rather than a checksum precisely so that
|
|
84
|
+
* second half stays readable. Its LIMIT, plainly: the pin is scoped to this
|
|
85
|
+
* floor section. It does not cover `AUDIT_UNREVIEWED_RESIDUE`, the posture
|
|
86
|
+
* sections, or `AUDIT_GUIDE_SHARED` (which carries its own byte pin against the
|
|
87
|
+
* MCP copy, in audit-guide-sync.test.ts).
|
|
88
|
+
*/
|
|
89
|
+
/** A candidate for anchoring, in the floor's own terms. */
|
|
90
|
+
export type AnchorCandidate = 'residue_or_restatement' | 'new_root_cause';
|
|
91
|
+
/** What the floor does with a candidate. */
|
|
92
|
+
export type AnchorDisposition = 'withhold' | 'anchor';
|
|
93
|
+
/**
|
|
94
|
+
* A fact a pass could mistake for the test. A factor named here is rendered as
|
|
95
|
+
* explicitly NOT deciding; it may never appear as a condition (tests pin that).
|
|
96
|
+
*/
|
|
97
|
+
export type NonDecidingFactor = 'criterion_coverage';
|
|
98
|
+
/**
|
|
99
|
+
* One normative rule of the floor: what happens to a candidate, and on what.
|
|
100
|
+
*
|
|
101
|
+
* Every field is a typed enum or a DECLARED list. There is deliberately no
|
|
102
|
+
* sentence field: the rule's sentence is composed from these fields, because a
|
|
103
|
+
* hand-written sentence is the one place a restriction can sit where no
|
|
104
|
+
* structural channel sees it.
|
|
105
|
+
*/
|
|
106
|
+
export interface AnchoringRule {
|
|
107
|
+
readonly candidate: AnchorCandidate;
|
|
108
|
+
readonly disposition: AnchorDisposition;
|
|
109
|
+
/**
|
|
110
|
+
* Conditions the disposition genuinely depends on. EMPTY means
|
|
111
|
+
* UNCONDITIONAL. This is the ONLY door through which a condition on
|
|
112
|
+
* anchoring can reach the rendered prompt.
|
|
113
|
+
*/
|
|
114
|
+
readonly conditions: readonly string[];
|
|
115
|
+
/** Facts that never decide this disposition; rendered as "not the test". */
|
|
116
|
+
readonly nonDeciding: readonly NonDecidingFactor[];
|
|
117
|
+
/** What is OWED when the disposition is exercised. An obligation is not a gate. */
|
|
118
|
+
readonly obligations: readonly string[];
|
|
119
|
+
}
|
|
120
|
+
/** One basis the criteria-standing section can report, with its own rules. */
|
|
121
|
+
export interface FloorBasis {
|
|
122
|
+
/** Machine token the standing section reports (or `read_failed`). */
|
|
123
|
+
readonly basis: string;
|
|
124
|
+
/** Whether this basis IS a floor. `no_criteria_declared` is NOT one. */
|
|
125
|
+
readonly isFloor: boolean;
|
|
126
|
+
/** Bolded opening of the rendered bullet. Context, never a disposition. */
|
|
127
|
+
readonly lead: string;
|
|
128
|
+
/** What the basis means, before any rule applies. Context, never a disposition. */
|
|
129
|
+
readonly situation: string;
|
|
130
|
+
readonly rules: readonly AnchoringRule[];
|
|
131
|
+
/** Closing clarification for the basis. Context, never a disposition. */
|
|
132
|
+
readonly caveat?: string;
|
|
133
|
+
}
|
|
134
|
+
/** The floor's whole normative content, in one declarable structure. */
|
|
135
|
+
export interface FloorPolicy {
|
|
136
|
+
/** Bolded opening of the universal paragraph. */
|
|
137
|
+
readonly universalLead: string;
|
|
138
|
+
/** Rules that hold at EVERY basis. */
|
|
139
|
+
readonly universal: readonly AnchoringRule[];
|
|
140
|
+
/** Closing prose of the universal paragraph. Context, never a disposition. */
|
|
141
|
+
readonly universalClosing: readonly string[];
|
|
142
|
+
readonly bases: readonly FloorBasis[];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The declared floor. Everything normative the floor says about what may be
|
|
146
|
+
* anchored is in the TYPED fields here; the prose below is generated from
|
|
147
|
+
* them, and the free-text fields carry context only.
|
|
148
|
+
*/
|
|
149
|
+
export declare const AUDIT_FLOOR_POLICY: FloorPolicy;
|
|
150
|
+
/** Where a rule is being stated: the universal paragraph, or one basis. */
|
|
151
|
+
export type RuleScope = 'universal' | 'basis';
|
|
152
|
+
/** A free-text field of the policy, with the path it sits at. */
|
|
153
|
+
export interface ProseField {
|
|
154
|
+
readonly path: string;
|
|
155
|
+
readonly text: string;
|
|
156
|
+
}
|
|
157
|
+
/** A prose field that has strayed into stating the floor's normative content. */
|
|
158
|
+
export interface FloorProseViolation {
|
|
159
|
+
readonly path: string;
|
|
160
|
+
readonly text: string;
|
|
161
|
+
readonly reason: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Every free-text field of the policy. `conditions` is deliberately absent: it
|
|
165
|
+
* IS the declared channel for a scope, and it is counted rather than banned.
|
|
166
|
+
*
|
|
167
|
+
* Exported so the suite can prove the equality pin COVERS this set (every
|
|
168
|
+
* field's exact text appears verbatim inside the pinned render) rather than
|
|
169
|
+
* trusting a hand-maintained field list that goes stale on the next addition.
|
|
170
|
+
*/
|
|
171
|
+
export declare function floorProseFields(policy?: FloorPolicy): readonly ProseField[];
|
|
172
|
+
/**
|
|
173
|
+
* Prose fields that state normative content IN A WORDING THESE LISTS KNOW. An
|
|
174
|
+
* empty result means "nothing recognised", NEVER "nothing normative" -- see the
|
|
175
|
+
* BACKSTOP note above for why no wording list can mean the latter. The
|
|
176
|
+
* completeness guarantee is the equality pin in audit-phase.test.ts; this only
|
|
177
|
+
* makes the recognised cases fail earlier, at load, with a named path. Exported
|
|
178
|
+
* so a test can demonstrate rejection on a mutated policy.
|
|
179
|
+
*/
|
|
180
|
+
export declare function findFloorProseViolations(policy?: FloorPolicy): readonly FloorProseViolation[];
|
|
181
|
+
/** Render the policy: the universal paragraph, then one bullet per basis. */
|
|
182
|
+
export declare function renderFloorPolicy(policy?: FloorPolicy): readonly string[];
|
|
183
|
+
/**
|
|
184
|
+
* The composed floor section: the pointer at the standing section (which
|
|
185
|
+
* states no rule about what may be anchored), then the rendered policy.
|
|
186
|
+
*/
|
|
187
|
+
export declare function renderFloorSection(policy?: FloorPolicy): readonly string[];
|
|
188
|
+
//# sourceMappingURL=audit-floor-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-floor-policy.d.ts","sourceRoot":"","sources":["../../src/audit/audit-floor-policy.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,wBAAwB,GAAG,gBAAgB,CAAC;AAE1E,4CAA4C;AAC5C,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACnD,mFAAmF;IACnF,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAC;IAC7C,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CACvC;AAcD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAoHhC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AA6F9C,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,WAAgC,GAAG,SAAS,UAAU,EAAE,CAkBhG;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,WAAgC,GACvC,SAAS,mBAAmB,EAAE,CAwBhC;AA2ED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,WAAgC,GAAG,SAAS,MAAM,EAAE,CAS7F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,WAAgC,GAAG,SAAS,MAAM,EAAE,CAS9F"}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
|
+
// Pinned by: packages/daemon/src/audit/audit-phase.test.ts
|
|
3
|
+
// PINNED-BY-END
|
|
4
|
+
/**
|
|
5
|
+
* The withhold half of the test, identical wherever it is stated: the same
|
|
6
|
+
* candidate, the same disposition, no conditions anywhere.
|
|
7
|
+
*/
|
|
8
|
+
const WITHHOLD_RESIDUE = {
|
|
9
|
+
candidate: 'residue_or_restatement',
|
|
10
|
+
disposition: 'withhold',
|
|
11
|
+
conditions: [],
|
|
12
|
+
nonDeciding: [],
|
|
13
|
+
obligations: [],
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The declared floor. Everything normative the floor says about what may be
|
|
17
|
+
* anchored is in the TYPED fields here; the prose below is generated from
|
|
18
|
+
* them, and the free-text fields carry context only.
|
|
19
|
+
*/
|
|
20
|
+
export const AUDIT_FLOOR_POLICY = {
|
|
21
|
+
universalLead: 'The floor stops ELABORATION, not new work.',
|
|
22
|
+
universal: [
|
|
23
|
+
WITHHOLD_RESIDUE,
|
|
24
|
+
{
|
|
25
|
+
candidate: 'new_root_cause',
|
|
26
|
+
disposition: 'anchor',
|
|
27
|
+
conditions: [],
|
|
28
|
+
nonDeciding: ['criterion_coverage'],
|
|
29
|
+
obligations: ['why the cause is new rather than residue or a restatement'],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
universalClosing: [
|
|
33
|
+
'Anchoring past a reached floor is a DECLARED act, never a silent one -- but it is declared by what you DRAW, not by what you write. On an armed focus a delivery that serves no effect the arm covers is recorded and waits for the next arm; to have it run now, draw the causal edge that makes it means. There is no reason field that substitutes for the edge.',
|
|
34
|
+
],
|
|
35
|
+
bases: [
|
|
36
|
+
{
|
|
37
|
+
basis: 'all_criteria_addressed',
|
|
38
|
+
isFloor: true,
|
|
39
|
+
lead: 'Basis `all_criteria_addressed` -- the floor is REACHED.',
|
|
40
|
+
situation: 'Every criterion the focus declared already has a delivery pointing at it, so there is no OPEN declared work to elaborate against.',
|
|
41
|
+
rules: [
|
|
42
|
+
WITHHOLD_RESIDUE,
|
|
43
|
+
{
|
|
44
|
+
candidate: 'new_root_cause',
|
|
45
|
+
disposition: 'anchor',
|
|
46
|
+
conditions: [],
|
|
47
|
+
nonDeciding: ['criterion_coverage'],
|
|
48
|
+
obligations: [
|
|
49
|
+
'why the cause is new rather than residue or a restatement',
|
|
50
|
+
'which criterion it touches',
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
caveat: 'Note what the basis does NOT mean: addressed is not MET. Whether the work satisfies a criterion is the focus review\'s judgement, not yours, so "the floor is reached" is never "the focus is done" -- it is "there is nothing further for THIS pass to ELABORATE".',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
basis: 'open_criteria_remain',
|
|
58
|
+
isFloor: false,
|
|
59
|
+
lead: 'Basis `open_criteria_remain` -- the open criteria ARE the remaining work.',
|
|
60
|
+
situation: 'Work against them by name: each injection you author should trace to an OPEN criterion, and your audit summary should say which.',
|
|
61
|
+
rules: [
|
|
62
|
+
{
|
|
63
|
+
candidate: 'new_root_cause',
|
|
64
|
+
disposition: 'anchor',
|
|
65
|
+
conditions: [],
|
|
66
|
+
nonDeciding: [],
|
|
67
|
+
obligations: [],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
caveat: 'A new delivery that addresses no open criterion needs an explicit reason for existing, stated in the summary.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
basis: 'no_criteria_declared',
|
|
74
|
+
isFloor: false,
|
|
75
|
+
lead: 'Basis `no_criteria_declared` -- this is NOT a floor.',
|
|
76
|
+
situation: 'A focus that declared no acceptance criteria has gone UNMEASURED, not arrived. The act that produces criteria is concrete and it is yours: give each delivery an injection (`telora_product_delivery` create/update with `injectionNodeId`), and state the declared future -- the `frt_statement` -- on every undesired effect that injection targets (`telora_reality_tree_node` update). Those futures ARE this focus\'s criteria: an arm stamps them as the bar, and verify judges them against reality. An empty set means that act has not happened here yet, which is a fact about the tree and never a measurement of the work.',
|
|
77
|
+
rules: [
|
|
78
|
+
WITHHOLD_RESIDUE,
|
|
79
|
+
{
|
|
80
|
+
candidate: 'new_root_cause',
|
|
81
|
+
disposition: 'anchor',
|
|
82
|
+
conditions: [],
|
|
83
|
+
nonDeciding: [],
|
|
84
|
+
obligations: [
|
|
85
|
+
'that this focus declares no criteria, so no floor could be computed for it',
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
caveat: 'Do not read the empty set as "everything is addressed", and do not read it as licence to elaborate without limit: judge each candidate on the tree\'s own evidence.',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
basis: 'derived_live_unarmed',
|
|
93
|
+
isFloor: false,
|
|
94
|
+
lead: 'Basis `derived_live_unarmed` -- there is no floor to reach yet.',
|
|
95
|
+
situation: 'This focus is UN-ARMED, so the criteria in that section are a PREVIEW of the bar an arm would stamp, derived live from the tree rather than recorded by any arm. Nothing has been stamped, so nothing can have been reached. That section also names the covered effects stating NO future -- what an arm would refuse on -- and the ones whose future is a machine draft; stating those futures is work owed before a human can arm this focus at all.',
|
|
96
|
+
rules: [
|
|
97
|
+
WITHHOLD_RESIDUE,
|
|
98
|
+
{
|
|
99
|
+
candidate: 'new_root_cause',
|
|
100
|
+
disposition: 'anchor',
|
|
101
|
+
conditions: [],
|
|
102
|
+
nonDeciding: [],
|
|
103
|
+
obligations: [
|
|
104
|
+
'that this focus is un-armed, so the criteria you read were a preview rather than a stamped bar',
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
caveat: 'Do not read a preview as a floor, and do not read it as licence to elaborate without limit: the futures it previews are the same ones an arm would hold this focus to.',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
basis: 'read_failed',
|
|
112
|
+
isFloor: false,
|
|
113
|
+
lead: 'If that section says READ FAILED, you have NO floor.',
|
|
114
|
+
situation: 'An unreadable standing is not evidence that every criterion is addressed.',
|
|
115
|
+
rules: [
|
|
116
|
+
WITHHOLD_RESIDUE,
|
|
117
|
+
{
|
|
118
|
+
candidate: 'new_root_cause',
|
|
119
|
+
disposition: 'anchor',
|
|
120
|
+
conditions: [],
|
|
121
|
+
nonDeciding: [],
|
|
122
|
+
obligations: ['that the standing was unreadable on this pass'],
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* CLOSED LEXICON (1/4): the subject of the normative sentence, chosen by the
|
|
130
|
+
* rule's `candidate`. Stated in full where the test is introduced, and short
|
|
131
|
+
* at each basis so the definition is given once rather than four times.
|
|
132
|
+
*/
|
|
133
|
+
const CANDIDATE_SUBJECT = {
|
|
134
|
+
universal: {
|
|
135
|
+
new_root_cause: 'A GENUINELY NEW ROOT CAUSE -- one no existing delivery already covers --',
|
|
136
|
+
residue_or_restatement: 'RESIDUE of work still in flight -- or a RESTATEMENT or refinement of a cause an existing delivery already covers --',
|
|
137
|
+
},
|
|
138
|
+
basis: {
|
|
139
|
+
new_root_cause: 'A genuinely new root cause',
|
|
140
|
+
residue_or_restatement: 'Residue, or a restatement or refinement of a cause already covered,',
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
/** CLOSED LEXICON (2/4): the same candidate named as the side of the test. */
|
|
144
|
+
const CANDIDATE_LABEL = {
|
|
145
|
+
new_root_cause: 'NEW ROOT CAUSE',
|
|
146
|
+
residue_or_restatement: 'RESIDUE OR RESTATEMENT',
|
|
147
|
+
};
|
|
148
|
+
/** CLOSED LEXICON (3/4): what the floor DOES, chosen by `disposition`. */
|
|
149
|
+
const DISPOSITION_VERB = {
|
|
150
|
+
anchor: 'is ANCHORED',
|
|
151
|
+
withhold: 'is WITHHELD',
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* CLOSED LEXICON (4/4): how a disposition with NO declared conditions states
|
|
155
|
+
* its own scope. An unconditional rule must SAY it is unconditional: a
|
|
156
|
+
* sentence that merely omits the scope is one a reader fills with the last
|
|
157
|
+
* rule they were taught.
|
|
158
|
+
*/
|
|
159
|
+
const UNCONDITIONAL_SCOPE = {
|
|
160
|
+
universal: {
|
|
161
|
+
anchor: 'at every basis below, in every case those bases can present, with nothing further to satisfy first',
|
|
162
|
+
withhold: 'at every basis below, in every case those bases can present',
|
|
163
|
+
},
|
|
164
|
+
basis: {
|
|
165
|
+
anchor: 'here, in every case this basis can present, with nothing further to satisfy first',
|
|
166
|
+
withhold: 'here, in every case this basis can present',
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Prose for each non-deciding factor. One sentence per factor, stated once
|
|
171
|
+
* here, so "coverage is not the test" cannot drift from rule to rule.
|
|
172
|
+
*/
|
|
173
|
+
const NON_DECIDING_PROSE = {
|
|
174
|
+
criterion_coverage: 'Whether a declared criterion already covers the ground a cause sits on is NOT the test and never decides it: coverage tells you whether declared work remains OPEN, it cannot tell you whether a cause is NEW.',
|
|
175
|
+
};
|
|
176
|
+
/** How an obligation sentence opens, per disposition. */
|
|
177
|
+
const OBLIGATION_LEAD = {
|
|
178
|
+
anchor: 'When you anchor, say in your audit summary',
|
|
179
|
+
withhold: 'When you withhold, say in your audit summary',
|
|
180
|
+
};
|
|
181
|
+
// ---- BACKSTOP: a fast, INCOMPLETE check on the policy's remaining prose ----
|
|
182
|
+
//
|
|
183
|
+
// Read this before trusting the rules below. They are an ENUMERATION of
|
|
184
|
+
// wordings, NOT the guarantee that context prose carries no restriction -- the
|
|
185
|
+
// equality pin on the rendered section is (round-8 note above). What they buy
|
|
186
|
+
// is EARLINESS and a NAMED reason: a claim in vocabulary they happen to know
|
|
187
|
+
// fails at module load with the offending path, instead of surfacing later as
|
|
188
|
+
// an unexplained diff against the pin. Stated limits:
|
|
189
|
+
// - the lists are finite, and no list can be complete. The two escapes review
|
|
190
|
+
// filed -- "Fresh findings wait for review." and "A genuinely new root
|
|
191
|
+
// cause proceeds after every existing delivery is reviewed." -- carry no
|
|
192
|
+
// listed noun/verb pair and no scope marker, so these rules PASS them. The
|
|
193
|
+
// pin rejects them.
|
|
194
|
+
// - they can only ADD rejections. Nothing reads a green result as evidence
|
|
195
|
+
// that prose is clean: a green backstop over a changed render is still RED.
|
|
196
|
+
// Widening the lists is allowed and harmless. It is not progress, and it must
|
|
197
|
+
// never be written up as closing the class.
|
|
198
|
+
/** Nouns that name one of the floor's candidates. Finite; not exhaustive. */
|
|
199
|
+
const CANDIDATE_NOUN = /\b(root causes?|residue|restatements?|refinements?)\b/i;
|
|
200
|
+
/** Verbs that state what the floor DOES with a candidate. Finite; not exhaustive. */
|
|
201
|
+
const DISPOSITION_VERB_IN_PROSE = /\b(anchors?|anchored|anchoring|withholds?|withheld|suppress(?:es|ed)?|defers?|deferred|skips?|skipped|omits?|omitted|excludes?|excluded)\b/i;
|
|
202
|
+
/** Markers that narrow a claim's scope. A scope is declared, never written. */
|
|
203
|
+
const SCOPE_MARKER = /\b(only|unless|except|solely|provided that|so long as|as long as|conditional on|contingent on)\b/i;
|
|
204
|
+
/**
|
|
205
|
+
* Every free-text field of the policy. `conditions` is deliberately absent: it
|
|
206
|
+
* IS the declared channel for a scope, and it is counted rather than banned.
|
|
207
|
+
*
|
|
208
|
+
* Exported so the suite can prove the equality pin COVERS this set (every
|
|
209
|
+
* field's exact text appears verbatim inside the pinned render) rather than
|
|
210
|
+
* trusting a hand-maintained field list that goes stale on the next addition.
|
|
211
|
+
*/
|
|
212
|
+
export function floorProseFields(policy = AUDIT_FLOOR_POLICY) {
|
|
213
|
+
const obligationsOf = (at, rules) => rules.flatMap((rule, j) => rule.obligations.map((text, k) => ({ path: `${at}.rules[${j}].obligations[${k}]`, text })));
|
|
214
|
+
const fields = [
|
|
215
|
+
{ path: 'universalLead', text: policy.universalLead },
|
|
216
|
+
...policy.universalClosing.map((text, i) => ({ path: `universalClosing[${i}]`, text })),
|
|
217
|
+
...obligationsOf('universal', policy.universal),
|
|
218
|
+
];
|
|
219
|
+
policy.bases.forEach((basis, i) => {
|
|
220
|
+
const at = `bases[${i}]`;
|
|
221
|
+
fields.push({ path: `${at}.lead`, text: basis.lead });
|
|
222
|
+
fields.push({ path: `${at}.situation`, text: basis.situation });
|
|
223
|
+
if (basis.caveat !== undefined)
|
|
224
|
+
fields.push({ path: `${at}.caveat`, text: basis.caveat });
|
|
225
|
+
fields.push(...obligationsOf(at, basis.rules));
|
|
226
|
+
});
|
|
227
|
+
return fields;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Prose fields that state normative content IN A WORDING THESE LISTS KNOW. An
|
|
231
|
+
* empty result means "nothing recognised", NEVER "nothing normative" -- see the
|
|
232
|
+
* BACKSTOP note above for why no wording list can mean the latter. The
|
|
233
|
+
* completeness guarantee is the equality pin in audit-phase.test.ts; this only
|
|
234
|
+
* makes the recognised cases fail earlier, at load, with a named path. Exported
|
|
235
|
+
* so a test can demonstrate rejection on a mutated policy.
|
|
236
|
+
*/
|
|
237
|
+
export function findFloorProseViolations(policy = AUDIT_FLOOR_POLICY) {
|
|
238
|
+
const violations = [];
|
|
239
|
+
for (const field of floorProseFields(policy)) {
|
|
240
|
+
if (CANDIDATE_NOUN.test(field.text) && DISPOSITION_VERB_IN_PROSE.test(field.text)) {
|
|
241
|
+
violations.push({
|
|
242
|
+
path: field.path,
|
|
243
|
+
text: field.text,
|
|
244
|
+
reason: 'states a DISPOSITION for a CANDIDATE in prose. That claim is composed from '
|
|
245
|
+
+ '`candidate` + `disposition` + `conditions`; written by hand it is the one place a '
|
|
246
|
+
+ 'restriction sits where no structural channel sees it.',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (SCOPE_MARKER.test(field.text)) {
|
|
250
|
+
violations.push({
|
|
251
|
+
path: field.path,
|
|
252
|
+
text: field.text,
|
|
253
|
+
reason: 'narrows a claim with a scope marker. A scope on the floor is declared in a rule\'s '
|
|
254
|
+
+ '`conditions`, where it is rendered as one clause and counted; context prose states none.',
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return violations;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Fail LOUDLY rather than compose a prompt that contradicts its own structure.
|
|
262
|
+
* The policy is a static constant, so a green test run is proof this can never
|
|
263
|
+
* throw at runtime; it throws at module load if someone edits prose into a
|
|
264
|
+
* normative claim THE BACKSTOP RECOGNISES. Prose it does not recognise composes
|
|
265
|
+
* fine here and is caught by the equality pin instead.
|
|
266
|
+
*/
|
|
267
|
+
function assertFloorProseIsContextOnly(policy) {
|
|
268
|
+
const violations = findFloorProseViolations(policy);
|
|
269
|
+
if (violations.length === 0)
|
|
270
|
+
return;
|
|
271
|
+
const detail = violations
|
|
272
|
+
.map((v) => ` ${v.path}: ${v.reason}\n text: ${v.text}`)
|
|
273
|
+
.join('\n');
|
|
274
|
+
throw new Error('audit floor policy: free-text field(s) carry normative content. The floor\'s normative '
|
|
275
|
+
+ 'claims are composed from the typed fields (candidate, disposition, conditions, '
|
|
276
|
+
+ 'nonDeciding); prose carries context only.\n' + detail);
|
|
277
|
+
}
|
|
278
|
+
/** Join clauses into one readable list ("a, b, and c"). */
|
|
279
|
+
function joinClauses(items) {
|
|
280
|
+
if (items.length < 2)
|
|
281
|
+
return items[0] ?? '';
|
|
282
|
+
return `${items.slice(0, -1).join(', ')}, and ${items[items.length - 1] ?? ''}`;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Render one rule as prose, entirely from its typed fields. A CONDITIONAL
|
|
286
|
+
* clause is emitted if and only if the rule declares conditions -- that
|
|
287
|
+
* one-to-one correspondence is what the tests count, so a freeze cannot be
|
|
288
|
+
* smuggled in as an extra sentence, and there is no sentence to write it in.
|
|
289
|
+
*/
|
|
290
|
+
function renderRule(rule, scope) {
|
|
291
|
+
const dispositionScope = rule.conditions.length > 0
|
|
292
|
+
? `only where ${joinClauses(rule.conditions)}`
|
|
293
|
+
: UNCONDITIONAL_SCOPE[scope][rule.disposition];
|
|
294
|
+
const parts = [
|
|
295
|
+
`${CANDIDATE_SUBJECT[scope][rule.candidate]} ${DISPOSITION_VERB[rule.disposition]} ${dispositionScope}.`,
|
|
296
|
+
];
|
|
297
|
+
for (const factor of rule.nonDeciding)
|
|
298
|
+
parts.push(NON_DECIDING_PROSE[factor]);
|
|
299
|
+
if (rule.obligations.length > 0) {
|
|
300
|
+
parts.push(`${OBLIGATION_LEAD[rule.disposition]} ${joinClauses(rule.obligations)}.`);
|
|
301
|
+
}
|
|
302
|
+
return parts.join(' ');
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Name the test, and state whether it holds everywhere. The "same test at
|
|
306
|
+
* every basis" half is COMPUTED against the bases rather than asserted, so a
|
|
307
|
+
* basis that departed from the universal rule would change this sentence
|
|
308
|
+
* instead of being contradicted by it.
|
|
309
|
+
*/
|
|
310
|
+
function renderTestSentence(policy) {
|
|
311
|
+
const universalDisposition = new Map(policy.universal.map((rule) => [rule.candidate, rule.disposition]));
|
|
312
|
+
const uniform = policy.bases.every((basis) => basis.rules.every((rule) => {
|
|
313
|
+
const declared = universalDisposition.get(rule.candidate);
|
|
314
|
+
return declared === undefined || (declared === rule.disposition && rule.conditions.length === 0);
|
|
315
|
+
}));
|
|
316
|
+
const sameness = uniform
|
|
317
|
+
? 'and it is the SAME test at every basis below'
|
|
318
|
+
: 'and the bases below depart from it -- read each one on its own terms';
|
|
319
|
+
return `The test is ${CANDIDATE_LABEL.residue_or_restatement} vs ${CANDIDATE_LABEL.new_root_cause}, ${sameness}.`;
|
|
320
|
+
}
|
|
321
|
+
/** Render one basis as a markdown bullet. */
|
|
322
|
+
function renderBasis(basis) {
|
|
323
|
+
const body = [basis.situation, ...basis.rules.map((rule) => renderRule(rule, 'basis'))];
|
|
324
|
+
if (basis.caveat !== undefined)
|
|
325
|
+
body.push(basis.caveat);
|
|
326
|
+
return `- **${basis.lead}** ${body.join(' ')}`;
|
|
327
|
+
}
|
|
328
|
+
/** Render the policy: the universal paragraph, then one bullet per basis. */
|
|
329
|
+
export function renderFloorPolicy(policy = AUDIT_FLOOR_POLICY) {
|
|
330
|
+
assertFloorProseIsContextOnly(policy);
|
|
331
|
+
const universal = [
|
|
332
|
+
`**${policy.universalLead}**`,
|
|
333
|
+
renderTestSentence(policy),
|
|
334
|
+
...policy.universal.map((rule) => renderRule(rule, 'universal')),
|
|
335
|
+
...policy.universalClosing,
|
|
336
|
+
].join(' ');
|
|
337
|
+
return [universal, '', ...policy.bases.map(renderBasis)];
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The composed floor section: the pointer at the standing section (which
|
|
341
|
+
* states no rule about what may be anchored), then the rendered policy.
|
|
342
|
+
*/
|
|
343
|
+
export function renderFloorSection(policy = AUDIT_FLOOR_POLICY) {
|
|
344
|
+
return [
|
|
345
|
+
'',
|
|
346
|
+
'## Before you anchor (round 5): has this focus reached its declared floor?',
|
|
347
|
+
'',
|
|
348
|
+
'The "Focus acceptance criteria standing" section of your context lists what this focus is FOR from both statements of it -- the futures of the undesired effects its arm covers, then its OWN declared acceptance criteria -- states for each its source and whether it is MET (verify recorded the future as landed), ADDRESSED (a current delivery points at it) or OPEN, and states the FLOOR with the basis it rests on. READ IT BEFORE YOU ANCHOR ANYTHING. It is the only thing in your context that says what this focus was for, and therefore the only thing that can tell you there is nothing left to anchor.',
|
|
349
|
+
'',
|
|
350
|
+
...renderFloorPolicy(policy),
|
|
351
|
+
];
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=audit-floor-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-floor-policy.js","sourceRoot":"","sources":["../../src/audit/audit-floor-policy.ts"],"names":[],"mappings":"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"}
|