Scribe is renamed Fabled Grimoire #212
@@ -1,7 +1,7 @@
|
||||
import { apiGet, apiPost, apiPut } from "@/api/client";
|
||||
|
||||
/**
|
||||
* Scheduled backups (milestone 523) — `/api/admin/backups`. One dated,
|
||||
* Scheduled backups — `/api/admin/backups`. One dated,
|
||||
* uncompressed tar per run, delivered to a folder or an S3 bucket.
|
||||
*/
|
||||
export interface BackupConfig {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Canonical systems — the GLOBAL area vocabulary every project's Systems can
|
||||
* map onto (milestone 307).
|
||||
* map onto.
|
||||
*
|
||||
* The mapping is an ASSOCIATION, never a rename: a project's System keeps the
|
||||
* name the project gave it, and `canonical_id` only records which shared area
|
||||
|
||||
@@ -55,7 +55,7 @@ export function apiErrorMessage(e: unknown, fallback: string): string {
|
||||
/**
|
||||
* How long an ordinary JSON call may wait before it is declared failed.
|
||||
*
|
||||
* Rule 156: a wait with no deadline is a bug. `fetch`'s own default is to wait
|
||||
* A wait with no deadline is a bug. `fetch`'s own default is to wait
|
||||
* as long as the browser will, which is not a deadline — it is the absence of
|
||||
* one, and it renders as a spinner that never resolves. There is no state a
|
||||
* surface can show for "pending forever" that is not a lie.
|
||||
@@ -118,7 +118,7 @@ export interface RequestOpts {
|
||||
* The one place a request is actually made — every verb below goes through
|
||||
* here, so the deadline cannot be forgotten by adding a sixth.
|
||||
*
|
||||
* EXPIRY SURFACES AS AN `ApiError`, which is rule 156's second half: the
|
||||
* EXPIRY SURFACES AS AN `ApiError`, the deadline's second half: the
|
||||
* failure has to arrive in the shape the caller already handles. A bare
|
||||
* `DOMException: TimeoutError` would reach `apiErrorMessage(e, fallback)` as
|
||||
* an object with no `body`, so every catch site in the app would report its
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Family canon (milestone 463): ideas every project on a platform shares, and
|
||||
* Family canon: ideas every project on a platform shares, and
|
||||
* the log of every decision about them.
|
||||
*
|
||||
* The agent promotes by written criteria — no approval step. This door is for
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/** Project inception (milestone 297): what a project was decided to inherit. */
|
||||
/** Project inception: what a project was decided to inherit. */
|
||||
import { apiGet, apiPost } from "@/api/client";
|
||||
import type { ProjectPlatform } from "@/api/platforms";
|
||||
|
||||
export interface InceptionChoices {
|
||||
design_system_id: number | null;
|
||||
seed_systems: boolean;
|
||||
/** Platform slugs (milestone 463). null = not answered; a list is the
|
||||
/** Platform slugs. null = not answered; a list is the
|
||||
* whole answer — members left out of it are recorded as "not this".
|
||||
* Absent on records decided before the question existed. */
|
||||
platforms?: string[] | null;
|
||||
|
||||
@@ -72,7 +72,7 @@ export interface Lesson {
|
||||
tags: string[];
|
||||
note_type: string;
|
||||
/** Where it was LEARNED. Kept as a fact, but not a limit on where it can be
|
||||
* found: a lesson is retrievable from every project (milestone 385 step 3). */
|
||||
* found: a lesson is retrievable from every project. */
|
||||
project_id: number | null;
|
||||
permission?: string;
|
||||
created_at: string | null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { apiGet, apiPost, apiDelete } from "@/api/client";
|
||||
|
||||
/**
|
||||
* The moments of work rules mount on (milestone 458), and the actions that
|
||||
* The moments of work rules mount on, and the actions that
|
||||
* reach each one on this install — `GET /api/retrieval/moments`, the payload
|
||||
* the `list_moments` MCP tool returns, plus the counts the Settings view shows
|
||||
* beside each moment.
|
||||
@@ -102,9 +102,8 @@ export function unmapAction(change: MappingChange): Promise<void> {
|
||||
|
||||
/**
|
||||
* Proposals about a rule's moments, waiting on a person. A `mount` proposal
|
||||
* (milestone 458 step 7) comes from a pass that read the rule, or from the
|
||||
* rule being opened just after the moment fired. An `unmount` proposal (step
|
||||
* 7b) comes from sessions reporting that the mount arrived where it did not
|
||||
* comes from a pass that read the rule, or from the rule being opened just
|
||||
* after the moment fired. An `unmount` proposal comes from sessions reporting that the mount arrived where it did not
|
||||
* apply. `GET /api/retrieval/moments/proposals`, the payload the
|
||||
* `rule_moment_proposals` MCP tool returns.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Platforms — what a project is built on or ships as (milestone 463).
|
||||
* Platforms — what a project is built on or ships as.
|
||||
*
|
||||
* The catalog is GLOBAL, like the canonical areas, and admin-written. A
|
||||
* project's answer per platform is `declared` (a person said so), `detected`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { apiGet } from "@/api/client";
|
||||
|
||||
/**
|
||||
* The reply shapes Scribe ships (milestone 500) — `GET /api/retrieval/reply-shapes`.
|
||||
* The reply shapes Scribe ships — `GET /api/retrieval/reply-shapes`.
|
||||
* The same catalog the `list_reply_shapes` MCP tool returns, plus what only
|
||||
* the operator's view needs: the preferences mounted on each shape's moment,
|
||||
* and how often each shape was delivered.
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { RecordUsage } from "@/types/usage";
|
||||
import { apiGet, apiPost, apiPatch, apiDelete } from "@/api/client";
|
||||
import type { LinkState } from "@/api/lessons";
|
||||
|
||||
/** How a rule reaches a session (milestone 307). */
|
||||
/** How a rule reaches a session. */
|
||||
|
||||
/**
|
||||
* A typed edge between two rules. Each kind exists because its absence forced
|
||||
@@ -56,7 +56,7 @@ export type RuleKind = "rule" | "preference";
|
||||
|
||||
/** A new record opened from somewhere that already knows what it is for —
|
||||
* "Adjust this" on a reply shape opens a preference mounted on that shape's
|
||||
* moment (milestone 500 step 5). The editor applies it once, when creating. */
|
||||
* moment. The editor applies it once, when creating. */
|
||||
export interface RulePreset {
|
||||
kind?: RuleKind;
|
||||
moments?: string[];
|
||||
@@ -91,11 +91,11 @@ export interface Rule {
|
||||
updated_at: string | null;
|
||||
/** Present only when the rule has them (the server omits empty keys). */
|
||||
systems?: { id: number; name: string }[];
|
||||
/** The moments this rule arrives at whenever they happen (milestone 458),
|
||||
/** The moments this rule arrives at whenever they happen,
|
||||
* in catalog order. Present only when the rule is mounted. */
|
||||
moments?: string[];
|
||||
relations?: RuleRelation[];
|
||||
/** The lessons that point at this rule (milestone 440) — the concrete
|
||||
/** The lessons that point at this rule — the concrete
|
||||
* situations judged instances of it, plus any suggested and awaiting a
|
||||
* judgment. Readable lessons only; omitted when there are none. */
|
||||
lessons?: { id: number; title: string; state: LinkState; note: string }[];
|
||||
@@ -124,7 +124,7 @@ export interface RuleHeader {
|
||||
*/
|
||||
last_verified?: string;
|
||||
/**
|
||||
* Surfaced-vs-opened counts from `rule_usage_events` (milestone 333).
|
||||
* Surfaced-vs-opened counts from `rule_usage_events`.
|
||||
* Zero-filled by the list route, so a rule predating the table reads as
|
||||
* "never surfaced" rather than as a missing field — which for a while is
|
||||
* every rule on every install.
|
||||
@@ -238,7 +238,7 @@ export async function updateRule(id: number, data: Partial<RuleWrite>): Promise<
|
||||
}
|
||||
|
||||
/** Give a rule a new home: a topic makes it global, a project makes it that
|
||||
* project's. Keeps its id, history, areas and relations (milestone 414). */
|
||||
* project's. Keeps its id, history, areas and relations. */
|
||||
export async function moveRule(
|
||||
id: number, to: { topic_id: number } | { project_id: number },
|
||||
): Promise<Rule> {
|
||||
@@ -295,7 +295,7 @@ export async function getRuleVersion(
|
||||
return apiGet<RuleVersion>(`/api/rules/${ruleId}/versions/${versionId}`);
|
||||
}
|
||||
|
||||
// No restore FOR A RULE, deliberately (milestone 323). Putting an old wording
|
||||
// No restore FOR A RULE, deliberately. Putting an old wording
|
||||
// back goes through updateRule, which snapshots what it replaces — so the
|
||||
// undo stays visible in the history like any other edit.
|
||||
//
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface Snippet {
|
||||
|
||||
/** Kept as a name because every consumer here says "snippet usage" — but it IS
|
||||
* the shared shape, since rules answer the same question off their own table
|
||||
* (milestone 333). The reasoning lives on `RecordUsage`; duplicating the four
|
||||
* The reasoning lives on `RecordUsage`; duplicating the four
|
||||
* fields here is how the two drift. */
|
||||
export type SnippetUsage = RecordUsage;
|
||||
|
||||
@@ -95,7 +95,7 @@ export interface SnippetListItem {
|
||||
* written, which is a shape to adapt rather than code to paste. */
|
||||
language?: string;
|
||||
/** When to reach for it, projected from the `data` mirror. The title is the
|
||||
* name alone since milestone 427, so this is where the situation lives. */
|
||||
* name alone, so this is where the situation lives. */
|
||||
when_to_use?: string;
|
||||
/** Always present from the backend, zero-filled for records with no events. */
|
||||
usage?: SnippetUsage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Moments (milestone 458): the pieces the rule editor's picker and the
|
||||
/* Moments: the pieces the rule editor's picker and the
|
||||
Settings section share, so a moment's name and a chip's remove control look
|
||||
the same wherever a person meets them. Loaded unscoped by both. */
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
milestone (tier, then verification) and were byte-identical; a third would
|
||||
have drifted. The pane's italic serif title is inherited by anything inside
|
||||
it, so the chip resets family and style explicitly. */
|
||||
/* A rule with no trigger cannot be retrieved, and since milestone 394
|
||||
retrieval is the only delivery — so this marks a rule that will never
|
||||
/* A rule with no trigger cannot be retrieved, and retrieval is the only
|
||||
delivery — so this marks a rule that will never
|
||||
reach a session. Warning rather than error: the rule is not broken, it is
|
||||
unreachable, and the fix is one field away. */
|
||||
.rule-chip-inert {
|
||||
|
||||
@@ -208,11 +208,8 @@
|
||||
*/
|
||||
|
||||
/* ==========================================================================
|
||||
The compatibility-alias block that lived here is GONE (#2533). It let ~55
|
||||
components keep their historical --color-* names while theme.css was
|
||||
repointed at the design system; the rename sweep it promised ran on
|
||||
2026-08-08 and every component now references --fs-* directly. Do not
|
||||
reintroduce app-local alias names — the design system's tokens are the
|
||||
Every component references the design system's --fs-* tokens directly.
|
||||
Do not introduce app-local alias names — the design system's tokens are the
|
||||
vocabulary, and check_snippets_against_design_system can only see through
|
||||
names the system actually declares.
|
||||
========================================================================== */
|
||||
|
||||
@@ -11,7 +11,7 @@ import { fmtStamp } from "@/utils/dateFormat";
|
||||
import { useToastStore } from "@/stores/toast";
|
||||
|
||||
/**
|
||||
* Scheduled backups (milestone 523): one dated, uncompressed tar per run,
|
||||
* Scheduled backups: one dated, uncompressed tar per run,
|
||||
* delivered to a folder or an S3 bucket. The page answers "is my data backed
|
||||
* up?" first — the verdict, then anything wrong — and the settings follow.
|
||||
*/
|
||||
@@ -50,7 +50,7 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
// While a backup runs, follow it. Re-armed from load()'s finally (rule 157),
|
||||
// While a backup runs, follow it. Re-armed from load()'s finally, never after the work,
|
||||
// so one failed read does not stop the page following the run.
|
||||
function schedulePoll() {
|
||||
if (pollTimer) clearTimeout(pollTimer);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* The adoption matrix (milestone 463 step 4): every project × every canon
|
||||
* The adoption matrix: every project × every canon
|
||||
* family idea that reaches it, and the project's answer.
|
||||
*
|
||||
* Nobody approves an answer — the agent assesses each project against the
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* The inception form (milestone 297): "what does this project inherit?"
|
||||
* The inception form: "what does this project inherit?"
|
||||
*
|
||||
* Two homes, one component. mode="create" rides the New-project modal's
|
||||
* second step and only emits the choices (the project does not exist yet);
|
||||
* mode="decide" sits on ProjectView for an undecided project, loads that
|
||||
* project's current defaults, and records the decision itself.
|
||||
*
|
||||
* Platforms (milestone 463) start UNANSWERED (null). Ticking any box makes
|
||||
* Platforms start UNANSWERED (null). Ticking any box makes
|
||||
* the list the whole answer; in decide mode the boxes start from what
|
||||
* detection already found, so recording confirms it.
|
||||
*/
|
||||
|
||||
@@ -8,9 +8,9 @@ import { useToastStore } from "@/stores/toast";
|
||||
|
||||
/**
|
||||
* Proposals about a rule's moments, waiting on a person. A mount proposal
|
||||
* (milestone 458 step 7) comes from a pass that read the rule, or from the
|
||||
* comes from a pass that read the rule, or from the
|
||||
* rule being opened just after the moment fired in several sessions; nothing
|
||||
* is mounted until "Mount" is pressed. An unmount proposal (step 7b) comes
|
||||
* is mounted until "Mount" is pressed. An unmount proposal comes
|
||||
* from sessions reporting that the mount arrived where it did not apply;
|
||||
* nothing is taken off until "Take it off" is pressed. Both are the judgment
|
||||
* `judge_rule_moments` makes in a session, through the same service.
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { MomentAction, MomentUsage } from "@/api/moments";
|
||||
import { fmtDate } from "@/utils/dateFormat";
|
||||
|
||||
/**
|
||||
* The human door onto moments (milestone 458 step 6): every moment in the
|
||||
* The human door onto moments: every moment in the
|
||||
* catalog, the actions that reach it on this install, how many rules ride on
|
||||
* it, and what reaching it has delivered. The session's own door is
|
||||
* `list_moments` / `map_action` / `unmap_action`, and both call the same
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* deliberately rather than abstracting: the ordering carries urgency, "never"
|
||||
* is categorically different from a date, and a failed check writes nothing.
|
||||
*
|
||||
* Lives in the Knowledge view rather than beside the rules sweep (operator's
|
||||
* call, milestone 317 step 4): notes stay where notes live. The cost, accepted
|
||||
* Lives in the Knowledge view rather than beside the rules sweep: notes stay
|
||||
* where notes live. The cost, accepted
|
||||
* knowingly, is that there is no single screen showing every record anyone has
|
||||
* left unconfirmed — /rules keeps its own.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* A project's place in the family (milestone 463): which platforms it is.
|
||||
* A project's place in the family: which platforms it is.
|
||||
*
|
||||
* Membership is what makes "does this family idea reach this project?" a
|
||||
* lookup rather than a judgment — an idea is for some platforms, and it
|
||||
|
||||
@@ -7,7 +7,7 @@ import RuleEditorSlideOver from "@/components/rules/RuleEditorSlideOver.vue";
|
||||
|
||||
/**
|
||||
* The reply shapes Scribe ships, and the operator's adjustments to each
|
||||
* (milestone 500 step 5). A shape is product, so its text is read-only here;
|
||||
* A shape is product, so its text is read-only here;
|
||||
* what the operator owns is the preferences mounted on the shape's moment,
|
||||
* which arrive beside it and win where they differ. "Adjust this" opens the
|
||||
* preference editor already mounted there.
|
||||
|
||||
@@ -570,7 +570,7 @@ async function confirmDelete() {
|
||||
.issue-systems { display: flex; gap: 0.25rem; flex-shrink: 0; flex-wrap: wrap; }
|
||||
.issue-sys-chip { font-size: 0.66rem; color: var(--fs-text-secondary); background: var(--fs-surface-raised); border-radius: 999px; padding: 0.05rem 0.4rem; }
|
||||
|
||||
/* ── Shared-area mapping (milestone 307) ──────────────────────────
|
||||
/* ── Shared-area mapping ──────────────────────────────────────────
|
||||
The review is a disclosure, not a banner: it exists only while there is
|
||||
something to decide, and collapses to one line until opened. */
|
||||
.area-review {
|
||||
@@ -700,7 +700,7 @@ async function confirmDelete() {
|
||||
.system-form-actions { display: flex; gap: 0.4rem; }
|
||||
.system-paths-input { font-family: var(--fs-font-mono); font-size: 0.8rem; }
|
||||
|
||||
/* The area's files (milestone 444). Mono because they are paths to be read
|
||||
/* The area's files. Mono because they are paths to be read
|
||||
character for character; small because they qualify the card, not lead it. */
|
||||
.system-paths {
|
||||
list-style: none;
|
||||
@@ -826,7 +826,7 @@ async function confirmDelete() {
|
||||
border: 1px dashed var(--fs-border-color);
|
||||
border-radius: var(--fs-radius-lg);
|
||||
}
|
||||
/* remainders over the shared recipes (components.css, m302) */
|
||||
/* remainders over the shared recipes (components.css) */
|
||||
.empty-title { margin: 0; color: var(--fs-text-primary); }
|
||||
.empty-sub { margin: 0 0 0.5rem; font-size: 0.82rem; max-width: 32ch; }
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
/**
|
||||
* "N/M used" on a list row — surfaced vs opened, for any record kind.
|
||||
*
|
||||
* Extracted from SnippetListView when the rule list needed the same chip
|
||||
* (milestone 333 step 5). The counts read identically for both; what differs
|
||||
* Shared by the snippet and rule lists. The counts read identically for both; what differs
|
||||
* is the ADVICE, which is why that is a prop. A snippet surfaced repeatedly
|
||||
* and never opened should probably go; a rule in the same position may simply
|
||||
* have a `when_to_apply` that fires on the wrong thing, and telling an
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* What Scribe has changed about how it works with you.
|
||||
*
|
||||
* THE RISK THIS EXISTS FOR (milestone 399). A preference is the one record
|
||||
* THE RISK THIS EXISTS FOR. A preference is the one record
|
||||
* kind the agent rewrites on its own, mid-work, without asking — which is
|
||||
* what keeps it current and what makes it dangerous. An agent misreads one
|
||||
* session, rewrites a preference, and follows the rewritten version forever
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { ApplicableRules } from "@/api/rulebooks";
|
||||
import RuleHomePicker from "@/components/rules/RuleHomePicker.vue";
|
||||
|
||||
/**
|
||||
* A project's view of its rules (milestone 414). A rule's home is its reach:
|
||||
* A project's view of its rules. A rule's home is its reach:
|
||||
* the project's own rules apply here and nowhere else, and every global rule
|
||||
* (one in a rulebook) applies here too. There is no subscribing this project
|
||||
* to a rulebook and no skipping a global rule for it — a project that departs
|
||||
|
||||
@@ -27,7 +27,7 @@ const whenToApply = ref("");
|
||||
// session may quietly rewrite.
|
||||
const kind = ref<RuleKind>("rule");
|
||||
const systemIds = ref<number[]>([]);
|
||||
// The moments this rule is mounted on (milestone 458). Catalog moments are
|
||||
// The moments this rule is mounted on. Catalog moments are
|
||||
// ticked; a named procedure's moment (`skill.<name>`) is typed, since its
|
||||
// name is the procedure's own and no list here could know it.
|
||||
const ruleMoments = ref<string[]>([]);
|
||||
@@ -46,7 +46,7 @@ const expiresWhen = ref("");
|
||||
|
||||
const relations = computed(() => store.currentRule?.relations ?? []);
|
||||
|
||||
// The lessons that point at this rule (milestone 440): confirmed instances
|
||||
// The lessons that point at this rule: confirmed instances
|
||||
// first, then suggestions waiting on a judgment. A rejected lesson does not
|
||||
// point at the rule, so it is not listed here — it stays readable on the
|
||||
// lesson, where the judgment was made.
|
||||
@@ -509,7 +509,7 @@ legend { padding: 0 0.35rem; font-size: 0.8rem; color: var(--fs-text-tertiary);
|
||||
.area-opt { display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.4rem; font-size: 0.88rem; }
|
||||
.area-opt input { width: auto; margin-top: 0.2rem; accent-color: var(--fs-accent); }
|
||||
.trigger-missing textarea { border-color: var(--fs-warning); }
|
||||
/* The moment picker (milestone 458): the name is what a session reads in a
|
||||
/* The moment picker: the name is what a session reads in a
|
||||
delivered line, so it is shown as written; the meaning is the gloss. */
|
||||
.moments { margin-bottom: 1rem; }
|
||||
.moments .intro { margin-top: 0; margin-bottom: var(--fs-space-3); }
|
||||
|
||||
@@ -84,7 +84,7 @@ function changedFields(index: number): string[] {
|
||||
/** True when this edit rewrote or removed the rule's check.
|
||||
*
|
||||
* Worth its own marker because editing `verify_with` silently drops
|
||||
* `verified_at` (milestone 312) — the moment a rule re-entered the staleness
|
||||
* `verified_at` — the moment a rule re-entered the staleness
|
||||
* sweep. That happens nowhere a reader can see it, and this row is the only
|
||||
* surface that can say when it happened. */
|
||||
function checkChanged(index: number): boolean {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* Where a rule lives, and moving it (milestone 414).
|
||||
* Where a rule lives, and moving it.
|
||||
*
|
||||
* A rule's home IS its reach: in a rulebook topic it is global and applies to
|
||||
* every project; on a project it applies there alone. Moving keeps the rule's
|
||||
|
||||
@@ -4,8 +4,7 @@ import { useRulebooksStore } from "@/stores/rulebooks";
|
||||
import type { RulebookTopic } from "@/api/rulebooks";
|
||||
|
||||
// A rulebook's rules are global — they apply to every project — so this pane
|
||||
// lists topics and nothing else. It carried a "Subscribers" checklist of
|
||||
// projects until milestone 414 retired subscriptions.
|
||||
// lists topics and nothing else.
|
||||
const props = defineProps<{
|
||||
rulebookId: number;
|
||||
topics: RulebookTopic[];
|
||||
|
||||
@@ -72,8 +72,8 @@ const router = createRouter({
|
||||
{
|
||||
// Lessons have no list view of their own: the Knowledge browse surface
|
||||
// is where every kind is enumerated, and a second list would be a
|
||||
// second vocabulary to keep in step with it (#3128's defect, in
|
||||
// advance). `/knowledge?type=lesson` is the list.
|
||||
// second vocabulary to keep in step with it. `/knowledge?type=lesson` is
|
||||
// the list.
|
||||
path: "/lessons/new",
|
||||
name: "lesson-new",
|
||||
component: () => import("@/views/LessonEditorView.vue"),
|
||||
@@ -129,7 +129,7 @@ const router = createRouter({
|
||||
component: () => import("@/views/RulesView.vue"),
|
||||
},
|
||||
{
|
||||
// Family canon (milestone 463): ideas shared across every project on a
|
||||
// Family canon: ideas shared across every project on a
|
||||
// platform, and the log of every decision about them.
|
||||
path: "/family",
|
||||
name: "family",
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useToastStore } from "@/stores/toast";
|
||||
import { apiErrorMessage } from "@/api/client";
|
||||
|
||||
/**
|
||||
* The global area catalog (milestone 307). Shared by every project, so it is
|
||||
* The global area catalog. Shared by every project, so it is
|
||||
* fetched ONCE per session rather than per project — the whole point of the
|
||||
* table is that it is the same list everywhere.
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useToastStore } from "@/stores/toast";
|
||||
import { apiErrorMessage } from "@/api/client";
|
||||
|
||||
/**
|
||||
* The moment catalog and this install's mappings (milestone 458 step 6).
|
||||
* The moment catalog and this install's mappings.
|
||||
*
|
||||
* Shared by the rule editor's picker and the Settings section, so the two
|
||||
* cannot offer different moments. The catalog is the product's and changes
|
||||
|
||||
@@ -4,10 +4,8 @@ import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client";
|
||||
import { useToastStore } from "@/stores/toast";
|
||||
import type { Note } from "@/types/note";
|
||||
|
||||
// Single-note + mutation surface. The list/filter/sort/pagination surface that
|
||||
// backed the removed /notes list view was dropped in the 2026-06-02 drift-audit
|
||||
// cleanup (no consumers — KnowledgeView and the editors use single-entity and
|
||||
// mutation methods only).
|
||||
// Single-note + mutation surface. There is no list/filter/sort here:
|
||||
// KnowledgeView and the editors use single-entity and mutation methods only.
|
||||
export const useNotesStore = defineStore("notes", () => {
|
||||
const currentNote = ref<Note | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as api from "@/api/platforms";
|
||||
import type { Platform } from "@/api/platforms";
|
||||
|
||||
/**
|
||||
* The global platform catalog (milestone 463). Shared by every project, so
|
||||
* The global platform catalog. Shared by every project, so
|
||||
* it is fetched once per session — as the canonical-area catalog is.
|
||||
*/
|
||||
export const usePlatformsStore = defineStore("platforms", () => {
|
||||
|
||||
@@ -142,7 +142,7 @@ export const useRulebooksStore = defineStore("rulebooks", () => {
|
||||
return rule;
|
||||
}
|
||||
|
||||
/** After a move (milestone 414): take the rule out of whichever topic list
|
||||
/** After a move: take the rule out of whichever topic list
|
||||
* held it, and into its new topic's list if that one is loaded. A rule moved
|
||||
* onto a project belongs to no topic list at all. */
|
||||
function placeMovedRule(rule: Rule) {
|
||||
|
||||
@@ -14,9 +14,8 @@ interface IssueFields {
|
||||
arose_from_id?: number | null;
|
||||
}
|
||||
|
||||
// Single-task + mutation surface. The list/filter/sort/pagination surface that
|
||||
// backed the removed /tasks list view was dropped in the 2026-06-02 drift-audit
|
||||
// cleanup (no consumers — ProjectView's kanban keeps its own local task list).
|
||||
// Single-task + mutation surface. There is no list/filter/sort here:
|
||||
// ProjectView's kanban keeps its own local task list.
|
||||
export const useTasksStore = defineStore("tasks", () => {
|
||||
const currentTask = ref<Task | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface Note {
|
||||
due_date: string | null;
|
||||
started_at: string | null;
|
||||
completed_at: string | null;
|
||||
// Which session is working this task now (milestone 381). Null when no
|
||||
// Which session is working this task now. Null when no
|
||||
// session ever claimed it; `live` false when the claim's lease ran out —
|
||||
// a session that went quiet mid-task, which is worth seeing, not hiding.
|
||||
claim?: TaskClaim | null;
|
||||
@@ -38,7 +38,7 @@ export interface Note {
|
||||
is_task: boolean;
|
||||
note_type: NoteType;
|
||||
task_kind?: TaskKind;
|
||||
// The note's own check (milestone 317). Empty on almost every note — that
|
||||
// The note's own check. Empty on almost every note — that
|
||||
// is the normal case: a note with no `verify_with` is a DECISION, and there
|
||||
// is nothing to go and check. Only a note asserting a fact about something
|
||||
// outside the operator's control carries one. `verified_at` null while
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* One shape for every record kind the retrieval surfaces can choose. Snippets
|
||||
* and notes are counted in `note_usage_events`; rules in `rule_usage_events`,
|
||||
* which is a separate table because a note id and a rule id are different
|
||||
* namespaces resolved through different maps at restore (milestone 333). The
|
||||
* namespaces resolved through different maps at restore. The
|
||||
* TABLES are separate for that reason; the READOUT is the same question, so
|
||||
* the client type is one.
|
||||
*
|
||||
@@ -21,7 +21,7 @@ export interface RecordUsage {
|
||||
last_surfaced_at: string | null;
|
||||
last_pulled_at: string | null;
|
||||
/** The subsets that happened on a project other than the record's own —
|
||||
* the evidence it transferred (milestone 385). Notes and snippets carry
|
||||
* the evidence it transferred. Notes and snippets carry
|
||||
* them; rules are global, so their readout does not. */
|
||||
surfaced_away_count?: number;
|
||||
pulled_away_count?: number;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
/**
|
||||
* Line diff — one copy, for every surface that shows what changed.
|
||||
*
|
||||
* WHY THIS FILE EXISTS. The same LCS walk was written out three times:
|
||||
* privately in `useAssist.ts`, and again inside `HistoryPanel.vue` and
|
||||
* `VersionHistorySection.vue`. The three were character-identical apart from
|
||||
* quote style — nobody had diverged them on purpose, they were simply copied
|
||||
* because `computeDiff` was never exported. Milestone 323 needed a fourth
|
||||
* consumer (a rule's edit history), and a fourth copy is the cost #3207
|
||||
* records: a fix or an improvement now has to be found in N places by someone
|
||||
* who does not know N.
|
||||
* WHY THIS FILE EXISTS. The one LCS diff walk, shared by `useAssist.ts`,
|
||||
* `HistoryPanel.vue`, `VersionHistorySection.vue` and the rule edit history.
|
||||
* A copy per consumer means a fix has to be found in N places by someone who
|
||||
* does not know N.
|
||||
*/
|
||||
|
||||
export interface DiffLine {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* Family canon (milestone 463): the ideas every project on a platform shares,
|
||||
* Family canon: the ideas every project on a platform shares,
|
||||
* and the log of every decision about them.
|
||||
*
|
||||
* Nobody approves a promotion — the agent decides against the three criteria
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* exists (#3727) — sessions were proposing rules for things that should never
|
||||
* have bound anyone.
|
||||
*
|
||||
* BUT IT CAN POINT AT ONE (milestone 440). A lesson that is an instance of a
|
||||
* BUT IT CAN POINT AT ONE. A lesson that is an instance of a
|
||||
* rule says so, and the page shows which of the three answers it holds: the
|
||||
* rule(s) it was judged an instance of, "no rule fits" with the reason, or
|
||||
* not yet judged. The third is the one worth acting on, so it is stated as
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
*
|
||||
* THREE FIELDS, NOT ONE MARKDOWN BOX. The title and body are composed by the
|
||||
* service from `what`, `when_to_apply` and `insight`; this form never sends a
|
||||
* document. That is the design milestone 385 step 1 settled on, and the
|
||||
* evidence for it is blunt: the snippet corpus carries a trigger on every
|
||||
* record with no guard anywhere, because a service composes the title from a
|
||||
* named parameter. What is at 100% is a named structured field — not a writer
|
||||
* remembering a convention.
|
||||
* document, because a field the service composes from a named parameter is
|
||||
* filled every time, with no guard anywhere — a writer remembering a
|
||||
* convention is not.
|
||||
*
|
||||
* THE TRIGGER IS THE FIELD THAT CANNOT BE MISSED, so it is given the most
|
||||
* room, its own explanation, and a save button that refuses without it. A
|
||||
@@ -17,7 +15,7 @@
|
||||
* surfaces — and there is nothing to notice afterwards, because it looks
|
||||
* exactly like a lesson that works. The form is where that gets caught.
|
||||
*
|
||||
* WHICH RULE IS THIS AN INSTANCE OF (milestone 440) is asked here, while the
|
||||
* WHICH RULE IS THIS AN INSTANCE OF is asked here, while the
|
||||
* writer still has the situation in mind, the same way the create tool asks
|
||||
* it. There are three answers: the rule(s), "no rule fits" with a reason, or
|
||||
* leave it open. None is forced, because a lesson left open is still a
|
||||
@@ -267,7 +265,7 @@ onMounted(() => {
|
||||
// Pre-fill from the link that brought you here, the same convention the
|
||||
// snippet editor uses. Left null it is a lesson with no recorded origin,
|
||||
// which is valid — `project_id` says where a lesson was LEARNED and was
|
||||
// never the limit on where it can be found (step 3).
|
||||
// never the limit on where it can be found.
|
||||
if (!isEdit.value && route.query.projectId) {
|
||||
projectId.value = Number(route.query.projectId);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ const projectId = ref<number | null>(null);
|
||||
const milestoneId = ref<number | null>(null);
|
||||
const noteType = ref<NoteType>("note");
|
||||
|
||||
// The note's own check (milestone 317). Offered only for a plain note: a
|
||||
// The note's own check. Offered only for a plain note: a
|
||||
// task's decay is its status, and a snippet has verify_snippet — the service
|
||||
// refuses both, so the form must not ask for what the save would reject.
|
||||
const verifyWith = ref("");
|
||||
@@ -509,7 +509,7 @@ onUnmounted(() => assist.clearSelection());
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- The note's own check (milestone 317). Shown only for a plain
|
||||
<!-- The note's own check. Shown only for a plain
|
||||
note: the service refuses a check on a task or a snippet, so
|
||||
offering the fields there would be a form whose save fails. -->
|
||||
<template v-if="canCarryCheck">
|
||||
|
||||
@@ -50,7 +50,7 @@ const newTitle = ref("");
|
||||
const newDescription = ref("");
|
||||
const newGoal = ref("");
|
||||
const creating = ref(false);
|
||||
// Step 2 of the modal (milestone 297): what the new project inherits.
|
||||
// Step 2 of the modal: what the new project inherits.
|
||||
const modalStep = ref<1 | 2>(1);
|
||||
const newInception = ref<InceptionChoices>(emptyChoices());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user