@isaacriehm/cairn-core 0.8.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/attention/bulk-accept.d.ts +0 -2
  3. package/dist/attention/bulk-accept.js +0 -3
  4. package/dist/attention/bulk-accept.js.map +1 -1
  5. package/dist/attention/scoring.d.ts +1 -3
  6. package/dist/attention/scoring.js +1 -12
  7. package/dist/attention/scoring.js.map +1 -1
  8. package/dist/claude/cache.js +1 -0
  9. package/dist/claude/cache.js.map +1 -1
  10. package/dist/claude/runner.js +25 -1
  11. package/dist/claude/runner.js.map +1 -1
  12. package/dist/claude/types.d.ts +8 -0
  13. package/dist/hooks/runners/payload.d.ts +10 -0
  14. package/dist/hooks/runners/payload.js +13 -0
  15. package/dist/hooks/runners/payload.js.map +1 -1
  16. package/dist/hooks/runners/session-end.js +2 -4
  17. package/dist/hooks/runners/session-end.js.map +1 -1
  18. package/dist/hooks/runners/session-start.js +48 -4
  19. package/dist/hooks/runners/session-start.js.map +1 -1
  20. package/dist/init/brand-derive.js +6 -1
  21. package/dist/init/brand-derive.js.map +1 -1
  22. package/dist/init/brand-setup.d.ts +12 -1
  23. package/dist/init/brand-setup.js +36 -1
  24. package/dist/init/brand-setup.js.map +1 -1
  25. package/dist/init/curator/corpus.d.ts +92 -0
  26. package/dist/init/curator/corpus.js +171 -0
  27. package/dist/init/curator/corpus.js.map +1 -0
  28. package/dist/init/curator/emit.d.ts +42 -0
  29. package/dist/init/curator/emit.js +230 -0
  30. package/dist/init/curator/emit.js.map +1 -0
  31. package/dist/init/curator/index.d.ts +1 -0
  32. package/dist/init/curator/index.js +2 -0
  33. package/dist/init/curator/index.js.map +1 -0
  34. package/dist/init/curator/regex-prefilter.d.ts +54 -0
  35. package/dist/init/curator/regex-prefilter.js +185 -0
  36. package/dist/init/curator/regex-prefilter.js.map +1 -0
  37. package/dist/init/curator/validate.d.ts +46 -0
  38. package/dist/init/curator/validate.js +100 -0
  39. package/dist/init/curator/validate.js.map +1 -0
  40. package/dist/init/curator/walker.d.ts +36 -0
  41. package/dist/init/curator/walker.js +380 -0
  42. package/dist/init/curator/walker.js.map +1 -0
  43. package/dist/init/eta-calibration.d.ts +39 -0
  44. package/dist/init/eta-calibration.js +143 -0
  45. package/dist/init/eta-calibration.js.map +1 -0
  46. package/dist/init/index.d.ts +3 -2
  47. package/dist/init/index.js +2 -1
  48. package/dist/init/index.js.map +1 -1
  49. package/dist/init/init.js +4 -20
  50. package/dist/init/init.js.map +1 -1
  51. package/dist/init/mapper-merge.d.ts +4 -6
  52. package/dist/init/mapper-merge.js +11 -34
  53. package/dist/init/mapper-merge.js.map +1 -1
  54. package/dist/init/mapper-parallel.d.ts +0 -1
  55. package/dist/init/mapper-parallel.js +7 -6
  56. package/dist/init/mapper-parallel.js.map +1 -1
  57. package/dist/init/mapper-prompts.d.ts +1 -4
  58. package/dist/init/mapper-prompts.js +2 -6
  59. package/dist/init/mapper-prompts.js.map +1 -1
  60. package/dist/init/mapper.d.ts +8 -7
  61. package/dist/init/mapper.js +23 -15
  62. package/dist/init/mapper.js.map +1 -1
  63. package/dist/init/overlay.js +0 -1
  64. package/dist/init/overlay.js.map +1 -1
  65. package/dist/init/phases/10-rules-merge.d.ts +7 -2
  66. package/dist/init/phases/10-rules-merge.js +18 -45
  67. package/dist/init/phases/10-rules-merge.js.map +1 -1
  68. package/dist/init/phases/13-multidev.d.ts +5 -1
  69. package/dist/init/phases/13-multidev.js +23 -2
  70. package/dist/init/phases/13-multidev.js.map +1 -1
  71. package/dist/init/phases/4-seed.js +1 -2
  72. package/dist/init/phases/4-seed.js.map +1 -1
  73. package/dist/init/phases/5-preflight.d.ts +42 -0
  74. package/dist/init/phases/5-preflight.js +244 -0
  75. package/dist/init/phases/5-preflight.js.map +1 -0
  76. package/dist/init/phases/7-topic-index.d.ts +6 -0
  77. package/dist/init/phases/7-topic-index.js +13 -0
  78. package/dist/init/phases/7-topic-index.js.map +1 -1
  79. package/dist/init/phases/8-docs-ingest.d.ts +6 -5
  80. package/dist/init/phases/8-docs-ingest.js +17 -56
  81. package/dist/init/phases/8-docs-ingest.js.map +1 -1
  82. package/dist/init/phases/9a-walker.d.ts +15 -0
  83. package/dist/init/phases/9a-walker.js +63 -0
  84. package/dist/init/phases/9a-walker.js.map +1 -0
  85. package/dist/init/phases/9b-curate.d.ts +19 -0
  86. package/dist/init/phases/9b-curate.js +79 -0
  87. package/dist/init/phases/9b-curate.js.map +1 -0
  88. package/dist/init/phases/9c-emit.d.ts +13 -0
  89. package/dist/init/phases/9c-emit.js +57 -0
  90. package/dist/init/phases/9c-emit.js.map +1 -0
  91. package/dist/init/phases/index.d.ts +6 -5
  92. package/dist/init/phases/index.js +4 -4
  93. package/dist/init/phases/index.js.map +1 -1
  94. package/dist/init/phases/mapper-output-io.d.ts +5 -5
  95. package/dist/init/phases/mapper-output-io.js +5 -5
  96. package/dist/init/phases/orchestrator.js +1 -1
  97. package/dist/init/phases/state-io.js +1 -1
  98. package/dist/init/phases/types.d.ts +79 -13
  99. package/dist/init/phases/types.js +4 -2
  100. package/dist/init/phases/types.js.map +1 -1
  101. package/dist/init/source-comments/ingest.d.ts +0 -2
  102. package/dist/init/source-comments/ingest.js.map +1 -1
  103. package/dist/init/source-comments/walker.js +2 -2
  104. package/dist/init/topic-index/index.d.ts +8 -0
  105. package/dist/init/topic-index/index.js +10 -2
  106. package/dist/init/topic-index/index.js.map +1 -1
  107. package/dist/init/topic-index/judge.d.ts +15 -0
  108. package/dist/init/topic-index/judge.js +15 -1
  109. package/dist/init/topic-index/judge.js.map +1 -1
  110. package/dist/init/topic-index/resolve.js +41 -14
  111. package/dist/init/topic-index/resolve.js.map +1 -1
  112. package/dist/init/walker.d.ts +1 -1
  113. package/dist/init/walker.js +1 -1
  114. package/dist/init/workflow-block.d.ts +5 -6
  115. package/dist/init/workflow-block.js +5 -9
  116. package/dist/init/workflow-block.js.map +1 -1
  117. package/dist/mcp/tools/bulk-accept-attention.d.ts +1 -1
  118. package/dist/mcp/tools/bulk-accept-attention.js +4 -6
  119. package/dist/mcp/tools/bulk-accept-attention.js.map +1 -1
  120. package/dist/mcp/tools/init-phases.d.ts +7 -6
  121. package/dist/mcp/tools/init-phases.js +34 -59
  122. package/dist/mcp/tools/init-phases.js.map +1 -1
  123. package/dist/session-start/build.js +47 -5
  124. package/dist/session-start/build.js.map +1 -1
  125. package/package.json +2 -2
  126. package/templates/.cairn/config/trust-policy.yaml +0 -3
  127. package/templates/.cairn/config/workflow.md +0 -1
  128. package/templates/.cairn/ground/canonical-map/topics.yaml +0 -12
  129. package/dist/init/phases/5-pilot.d.ts +0 -10
  130. package/dist/init/phases/5-pilot.js +0 -108
  131. package/dist/init/phases/5-pilot.js.map +0 -1
  132. package/dist/init/phases/9-source-comments.d.ts +0 -6
  133. package/dist/init/phases/9-source-comments.js +0 -67
  134. package/dist/init/phases/9-source-comments.js.map +0 -1
  135. package/dist/init/phases/parallel-8910.d.ts +0 -27
  136. package/dist/init/phases/parallel-8910.js +0 -197
  137. package/dist/init/phases/parallel-8910.js.map +0 -1
  138. package/dist/init/phases/source-comments-output-io.d.ts +0 -89
  139. package/dist/init/phases/source-comments-output-io.js +0 -81
  140. package/dist/init/phases/source-comments-output-io.js.map +0 -1
  141. package/templates/.cairn/ground/capabilities/mcp-tools.yaml +0 -29
  142. package/templates/.cairn/ground/capabilities/skills.yaml +0 -25
  143. package/templates/.cairn/ground/capabilities/snippets.yaml +0 -29
@@ -1,89 +0,0 @@
1
- /**
2
- * Side-file persistence for the heavy Phase 9 output.
3
- *
4
- * `IngestSourceCommentsResult` carries the full walk (every comment block's
5
- * raw text + prose) and the matching classifications. On a busy monorepo
6
- * this crosses ~1.7 MB — far above what the MCP transport can echo back
7
- * in a tool result. Mirrors the v0.3.5 mapper-output spillover: write the
8
- * full payload to `.cairn/init/source-comments-walk.json` and persist a
9
- * lightweight projection (counts, paths, ledger-relevant lists) into
10
- * `init-state.json`.
11
- *
12
- * Downstream phases consume only the lightweight projection — the
13
- * heavy walk + per-block classifications already live in
14
- * `.cairn/baseline/source-comments-<ISO>.yaml` (the audit YAML), which
15
- * the strip-replace stage and any later debug tools already read.
16
- */
17
- import type { IngestSourceCommentsResult } from "../source-comments/index.js";
18
- import type { CommentClassKind } from "../source-comments/classify.js";
19
- /** Filename relative to repoRoot. */
20
- export declare const SOURCE_COMMENTS_WALK_PATH: string;
21
- export declare function sourceCommentsWalkAbsPath(repoRoot: string): string;
22
- /**
23
- * Atomically write the full Phase 9 result. Creates `.cairn/init/`
24
- * if needed.
25
- */
26
- export declare function writeSourceCommentsWalkFile(repoRoot: string, full: IngestSourceCommentsResult): string;
27
- /**
28
- * Read the full Phase 9 result from `.cairn/init/source-comments-walk.json`.
29
- * Returns null if missing or unreadable. Available for debug tooling and
30
- * post-hoc inspection — phase consumers prefer the lightweight projection
31
- * stored on state.
32
- */
33
- export declare function readSourceCommentsWalkFile(repoRoot: string): IngestSourceCommentsResult | null;
34
- /** Phase was skipped because the repo is the Cairn source repo itself. */
35
- export interface IngestSourceCommentsSkippedResult {
36
- readonly skipped: "self-adopt";
37
- }
38
- /**
39
- * Lightweight projection persisted into `init-state.json` outputs. Drops
40
- * `walk.blocks` and `classifications` (the heavy fields); keeps ledger /
41
- * triage references that downstream phases + the cairn-adopt summary
42
- * skill query directly.
43
- */
44
- export interface IngestSourceCommentsRunResult {
45
- /** Repo-relative path to the spilled full result, or null when not written. */
46
- walkPath: string;
47
- walkSummary: {
48
- files: number;
49
- blocks: number;
50
- bytesScanned: number;
51
- fileCountByLang: Record<string, number>;
52
- filesAvailable: number;
53
- truncatedAtFileCap: boolean;
54
- };
55
- decsWritten: {
56
- id: string;
57
- path: string;
58
- sourceFile: string;
59
- slug: string;
60
- status: "accepted";
61
- }[];
62
- invsWritten: {
63
- id: string;
64
- path: string;
65
- sourceFile: string;
66
- slug: string;
67
- status: "accepted";
68
- }[];
69
- citesEmitted: {
70
- id: string;
71
- sourceFile: string;
72
- lineRange: [number, number];
73
- slug: string;
74
- }[];
75
- stripFilesModified: number;
76
- stripItemsApplied: number;
77
- stripItemsSkipped: number;
78
- stripError: string | null;
79
- auditPath: string;
80
- auditRelPath: string;
81
- inputTokens: number;
82
- outputTokens: number;
83
- batchesRun: number;
84
- batchesFailed: number;
85
- kindCounts: Record<CommentClassKind, number>;
86
- }
87
- export type IngestSourceCommentsResultPersisted = IngestSourceCommentsRunResult | IngestSourceCommentsSkippedResult;
88
- /** Strip the heavy fields from a fresh ingest result for state persistence. */
89
- export declare function to7bResultPersisted(full: IngestSourceCommentsResult): IngestSourceCommentsRunResult;
@@ -1,81 +0,0 @@
1
- /**
2
- * Side-file persistence for the heavy Phase 9 output.
3
- *
4
- * `IngestSourceCommentsResult` carries the full walk (every comment block's
5
- * raw text + prose) and the matching classifications. On a busy monorepo
6
- * this crosses ~1.7 MB — far above what the MCP transport can echo back
7
- * in a tool result. Mirrors the v0.3.5 mapper-output spillover: write the
8
- * full payload to `.cairn/init/source-comments-walk.json` and persist a
9
- * lightweight projection (counts, paths, ledger-relevant lists) into
10
- * `init-state.json`.
11
- *
12
- * Downstream phases consume only the lightweight projection — the
13
- * heavy walk + per-block classifications already live in
14
- * `.cairn/baseline/source-comments-<ISO>.yaml` (the audit YAML), which
15
- * the strip-replace stage and any later debug tools already read.
16
- */
17
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
18
- import { dirname, join } from "node:path";
19
- /** Filename relative to repoRoot. */
20
- export const SOURCE_COMMENTS_WALK_PATH = join(".cairn", "init", "source-comments-walk.json");
21
- export function sourceCommentsWalkAbsPath(repoRoot) {
22
- return join(repoRoot, SOURCE_COMMENTS_WALK_PATH);
23
- }
24
- /**
25
- * Atomically write the full Phase 9 result. Creates `.cairn/init/`
26
- * if needed.
27
- */
28
- export function writeSourceCommentsWalkFile(repoRoot, full) {
29
- const abs = sourceCommentsWalkAbsPath(repoRoot);
30
- mkdirSync(dirname(abs), { recursive: true });
31
- const tmp = `${abs}.tmp`;
32
- writeFileSync(tmp, JSON.stringify(full, null, 2), "utf8");
33
- renameSync(tmp, abs);
34
- return abs;
35
- }
36
- /**
37
- * Read the full Phase 9 result from `.cairn/init/source-comments-walk.json`.
38
- * Returns null if missing or unreadable. Available for debug tooling and
39
- * post-hoc inspection — phase consumers prefer the lightweight projection
40
- * stored on state.
41
- */
42
- export function readSourceCommentsWalkFile(repoRoot) {
43
- const abs = sourceCommentsWalkAbsPath(repoRoot);
44
- if (!existsSync(abs))
45
- return null;
46
- try {
47
- return JSON.parse(readFileSync(abs, "utf8"));
48
- }
49
- catch {
50
- return null;
51
- }
52
- }
53
- /** Strip the heavy fields from a fresh ingest result for state persistence. */
54
- export function to7bResultPersisted(full) {
55
- return {
56
- walkPath: SOURCE_COMMENTS_WALK_PATH,
57
- walkSummary: {
58
- files: full.walk.files.length,
59
- blocks: full.walk.blocks.length,
60
- bytesScanned: full.walk.bytesScanned,
61
- fileCountByLang: full.walk.fileCountByLang,
62
- filesAvailable: full.walk.filesAvailable,
63
- truncatedAtFileCap: full.walk.truncatedAtFileCap,
64
- },
65
- decsWritten: full.decsWritten,
66
- invsWritten: full.invsWritten,
67
- citesEmitted: full.citesEmitted,
68
- stripFilesModified: full.stripFilesModified,
69
- stripItemsApplied: full.stripItemsApplied,
70
- stripItemsSkipped: full.stripItemsSkipped,
71
- stripError: full.stripError,
72
- auditPath: full.auditPath,
73
- auditRelPath: full.auditRelPath,
74
- inputTokens: full.inputTokens,
75
- outputTokens: full.outputTokens,
76
- batchesRun: full.batchesRun,
77
- batchesFailed: full.batchesFailed,
78
- kindCounts: full.kindCounts,
79
- };
80
- }
81
- //# sourceMappingURL=source-comments-output-io.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"source-comments-output-io.js","sourceRoot":"","sources":["../../../src/init/phases/source-comments-output-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAI1C,qCAAqC;AACrC,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAC3C,QAAQ,EACR,MAAM,EACN,2BAA2B,CAC5B,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,OAAO,IAAI,CAAC,QAAQ,EAAE,yBAAyB,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAgB,EAChB,IAAgC;IAEhC,MAAM,GAAG,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAChD,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC;IACzB,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1D,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrB,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAgB;IAEhB,MAAM,GAAG,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAA+B,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AA6DD,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CACjC,IAAgC;IAEhC,OAAO;QACL,QAAQ,EAAE,yBAAyB;QACnC,WAAW,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAC7B,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;YAC/B,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe;YAC1C,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc;YACxC,kBAAkB,EAAE,IAAI,CAAC,IAAI,CAAC,kBAAkB;SACjD;QACD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC;AACJ,CAAC"}
@@ -1,29 +0,0 @@
1
- # MCP servers registered alongside Cairn in .mcp.json.
2
- #
3
- # WHAT THIS FILE IS
4
- #
5
- # Inventory of the OTHER MCP servers this project uses (not cairn
6
- # itself — cairn auto-registers via the plugin bundle). Includes
7
- # server name + one-line capability summary. Read at SessionStart
8
- # so the agent knows what tools it can reach without re-listing
9
- # every tool exhaustively.
10
- #
11
- # WHEN TO FILL IT IN
12
- #
13
- # Operator-paced. Add an entry every time you wire up a new MCP
14
- # server (Notion, Stripe, internal tools, etc.). Flip an entry's
15
- # status when the server's capabilities shift.
16
- #
17
- # FORMAT
18
- #
19
- # Two examples to anchor on:
20
- #
21
- # mcp_tools:
22
- # - name: stripe
23
- # description: Stripe payments + customers + subscriptions. Use when the agent needs to look up a charge by id or check a customer's billing state.
24
- # status: accepted
25
- # - name: notion
26
- # description: Read-only Notion workspace query. Use for cross-referencing PRDs that live in Notion, never for writes.
27
- # status: accepted
28
-
29
- mcp_tools: []
@@ -1,25 +0,0 @@
1
- # Installed skill packs available in this session.
2
- #
3
- # WHAT THIS FILE IS
4
- #
5
- # Inventory of project-level skills the agent can invoke (the
6
- # `.claude/skills/` directory of the host project). Each entry is
7
- # name + one-line trigger description. Adoption seeds entries from
8
- # whatever's already in `.claude/skills/`; operator extends.
9
- #
10
- # WHEN TO FILL IT IN
11
- #
12
- # Auto-populated at adoption + on `cairn fix` re-scans. Edit by
13
- # hand only when adding a new project-local skill or removing one.
14
- #
15
- # FORMAT
16
- #
17
- # Two examples to anchor on:
18
- #
19
- # skills:
20
- # - name: deploy-staging
21
- # description: Push current branch to the staging GKE cluster + run smoke tests. Auto-invoke on "deploy", "ship", "push to staging".
22
- # - name: db-migrate
23
- # description: Generate + apply a Drizzle migration with backup snapshot. Auto-invoke when schema changes are mentioned.
24
-
25
- skills: []
@@ -1,29 +0,0 @@
1
- # Blessed implementations for security-sensitive patterns.
2
- #
3
- # WHAT THIS FILE IS
4
- #
5
- # A catalog of pattern → canonical-implementation pointers for code
6
- # the operator wants Claude to NEVER reinvent. Each entry says "if
7
- # you need to do X, copy from this exact location". Read at
8
- # SessionStart so the agent skips improvising auth / signing /
9
- # input-validation / etc.
10
- #
11
- # WHEN TO FILL IT IN
12
- #
13
- # Operator-paced. Add an entry every time you catch the agent
14
- # hand-rolling something that has an existing blessed implementation
15
- # in your codebase.
16
- #
17
- # FORMAT
18
- #
19
- # Two examples to anchor on:
20
- #
21
- # snippets:
22
- # - pattern: jwt-signing
23
- # canonical: src/auth/sign.ts:signSession
24
- # why: Single source of HS256 secret + iat. Hand-rolled JWT signing has historically leaked the secret in test fixtures.
25
- # - pattern: html-escape
26
- # canonical: src/util/escape.ts:escape
27
- # why: Uses the project's content-security-policy-aware escape; ad-hoc replace() chains miss attribute-context cases.
28
-
29
- snippets: []