From fb39cf04e31db525bafc4f23aa64a2e30efc3053 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Wed, 30 Sep 2026 13:43:22 -0400 Subject: [PATCH] Ground fleet ownership in bounded observed repository files --- docs/TEST_INTEGRITY.md | 26 ++++++++++++ docs/TODO.md | 14 +++++++ .../observed-file-ownership-2026-09-30.md | 28 +++++++++++++ src/cli.mjs | 2 +- src/design/architect.mjs | 6 +++ src/kernel/analyze.mjs | 4 ++ test/fleet/spec-design.test.mjs | 40 +++++++++++++++++++ 7 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 reports/audit/observed-file-ownership-2026-09-30.md diff --git a/docs/TEST_INTEGRITY.md b/docs/TEST_INTEGRITY.md index 087b3a4..c88024f 100644 --- a/docs/TEST_INTEGRITY.md +++ b/docs/TEST_INTEGRITY.md @@ -1,5 +1,31 @@ # Test Integrity Notes +## 2026-09-30 — Exact observed-file ownership evidence + +```yaml +test_integrity_note: + change_type: new_tests + scenarios: + - id: SCN-architect-file-ownership + given: A committed project with a README, package manifest and JSON schema + when: The Architect assigns observed files or invents absent files and directory globs + then: Observed-file claims validate, invented claims fail, and oversized exact evidence reports truncation + observable_outcomes: + - Public pending-proposal validity, invented-path and unknown-evidence diagnostics + - Exact evidence capped at 1000 files with explicit OWNERSHIP_EVIDENCE_TRUNCATED finding + determinism_controls: + - Disposable local Git history and fixed generated filenames + - No provider calls, timers, network, retries or sleeps + anti_cheat_rationale: + prevents: + - Assigning arbitrary unseen paths merely because metadata is not a source component + - Leaving schemas and manifests permanently unassignable despite observed evidence + - Claiming whole-repository ownership coverage from a truncated inventory + relaxation: + did_relax_any_assertion: false + if_true_explain_spec_basis: "" +``` + ## 2026-09-30 — Specialist-only project bootstrap ```yaml diff --git a/docs/TODO.md b/docs/TODO.md index a16e3a3..a1b20a4 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -4,6 +4,20 @@ ## Fresh readiness audit (2026-09-30) +Current checkpoint: `03fcbdd` committed the portable rewrite. The protected fixture +remains untracked and excluded. A commit-bound candidate passed all 38 acceptance +groups in an isolated temporary version store; it is inactive and no stable +launcher was installed. Older dirty-source/pending-checkpoint statements below +are historical snapshots, not the current commit state. + +Install-readiness follow-up: exact observed-file ownership evidence now permits +reviewable primary ownership for package metadata, schemas, documentation and +other deliverables, without admitting unobserved paths or invented directory +globs. Evidence is capped at 1000 entries with explicit truncation. Thirteen +focused scenarios and all 38 source acceptance groups PASS. Re-checkpoint this +fix, regenerate a complete six-area proposal and qualify its stopped-install +rehearsal before requesting real installation or live provider launch. + Self-host ownership follow-up: see `reports/audit/self-host-roster-review-2026-09-30.md`. A proposed six-specialist grouping covers 124 current implementation/assets/harness/test files with zero diff --git a/reports/audit/observed-file-ownership-2026-09-30.md b/reports/audit/observed-file-ownership-2026-09-30.md new file mode 100644 index 0000000..08c4408 --- /dev/null +++ b/reports/audit/observed-file-ownership-2026-09-30.md @@ -0,0 +1,28 @@ +# Install-readiness: exact observed-file ownership + +The Architect previously allowed source-component and specification globs but +could reject primary claims for observed non-source files such as package metadata +and JSON schemas. Sharing those files was allowed, yet their accountable primary +owner could remain unresolved. This blocked a complete TORCH self-host roster. + +Repository analysis now carries at most 1000 exact observed ownership paths plus +an explicit truncation flag. Pending proposal validation permits those paths as +ownership and evidence without inventing a directory glob or an absent file. +Truncated inventories return an ownership-review finding; source-component +coverage is not a claim of whole-repository coverage. Existing primary-collision +and pending owner-review requirements remain enforced. + +`SCN-architect-file-ownership` exercises README, package manifest and JSON schema +assignment, rejects absent paths/traversal/unobserved directory globs, and uses +over 1000 real disposable files to enforce the bound and diagnostic. It is now +required by candidate acceptance. No previous test expectation was weakened. + +Verification: thirteen focused design/domain scenarios PASS, focused ESLint and +diff hygiene PASS, all 38 isolated source acceptance groups PASS with test/lint/ +syntax statuses zero. Receipt: +`/tmp/torch-observed-file-ownership-20260930-acceptance.json`. + +This change does not approve TORCH's roster, activate a reporting graph, install +a stable launcher, start a provider or enable a timer. The accepted `03fcbdd` +candidate remains bound to its older source; qualify a new committed candidate +after this follow-up, not the old receipt against the modified tree. diff --git a/src/cli.mjs b/src/cli.mjs index c7b39f5..6a009c5 100644 --- a/src/cli.mjs +++ b/src/cli.mjs @@ -404,7 +404,7 @@ export const CANDIDATE_ACCEPTANCE_EVIDENCE = Object.freeze({ 'init-analyze': ['SCN-init-read-only'], 'spec-aware-design': ['SCN-spec-fleet-design', 'SCN-cli-spec-design'], 'ai-fleet-bootstrap': ['SCN-ai-fleet-bootstrap', 'SCN-bootstrap-specialist-only'], - 'ai-fleet-planning': ['SCN-ai-fleet-planning', 'SCN-architect-organization-assessment', 'SCN-bootstrap-primary-ownership'], + 'ai-fleet-planning': ['SCN-ai-fleet-planning', 'SCN-architect-organization-assessment', 'SCN-bootstrap-primary-ownership', 'SCN-architect-file-ownership'], 'fleet-evolution': ['SCN-fleet-evolution', 'SCN-cli-fleet-evolution'], 'fleet-boundary-evolution': ['SCN-fleet-boundary-evolution'], 'cli-lifecycle-surface': ['SCN-cli-lifecycle-surface'], diff --git a/src/design/architect.mjs b/src/design/architect.mjs index 2728234..e5286d4 100644 --- a/src/design/architect.mjs +++ b/src/design/architect.mjs @@ -61,6 +61,7 @@ function providerResponse(provider, result) { function allowedEvidence(brief) { const values = new Set(); + for (const path of brief.reconnaissance.inventory?.ownershipPaths ?? []) values.add(path); for (const component of brief.reconnaissance.architecture.components ?? []) { component.evidence.forEach((entry) => values.add(entry)); } @@ -74,6 +75,7 @@ function allowedEvidence(brief) { function allowedOwnedPaths(brief) { const values = new Set(); + for (const path of brief.reconnaissance.inventory?.ownershipPaths ?? []) values.add(path); for (const component of brief.reconnaissance.architecture.components ?? []) { component.paths.forEach((entry) => values.add(entry)); } @@ -164,6 +166,10 @@ export function createArchitectRunPlan({ brief, provider, model, maxBudgetUsd } export function validateArchitectProposal({ brief, proposal } = {}) { const problems = []; const findings = []; + if (brief?.reconnaissance?.inventory?.ownershipPathsTruncated) { + findings.push({ severity: 'review', code: 'OWNERSHIP_EVIDENCE_TRUNCATED', + message: 'Exact file ownership evidence is bounded; component coverage does not prove whole-repository ownership.' }); + } if (brief?.schema !== 'torch.dev/fleet-design-brief/v1alpha1') problems.push('unsupported design brief schema'); if (proposal?.schema !== 'torch.dev/domain-proposal/v1alpha1') problems.push('unsupported proposal schema'); if (proposal?.review?.status !== 'pending' || proposal?.review?.reviewedAt || proposal?.review?.reviewedBy) { diff --git a/src/kernel/analyze.mjs b/src/kernel/analyze.mjs index 1951d9b..cfb8505 100644 --- a/src/kernel/analyze.mjs +++ b/src/kernel/analyze.mjs @@ -77,6 +77,10 @@ export function analyzeRepository(repository, { specifications = [] } = {}) { trackedFileCount: workingTree.trackedFileCount, untrackedFileCount: workingTree.untrackedFileCount, analyzedFileCount: files.length, + // Exact observed files supplement source-component globs for manifests, + // documentation, schemas and other non-code deliverables. Keep briefs bounded. + ownershipPaths: files.slice(0, 1000), + ownershipPathsTruncated: files.length > 1000, languages, manifests, topLevelDirectories: [...topLevel].sort(), diff --git a/test/fleet/spec-design.test.mjs b/test/fleet/spec-design.test.mjs index 676514a..d9026d2 100644 --- a/test/fleet/spec-design.test.mjs +++ b/test/fleet/spec-design.test.mjs @@ -155,6 +155,46 @@ test('SCN-ai-fleet-bootstrap: startup emits a bounded Session Architect brief in }); +test('SCN-architect-file-ownership: observed metadata and deliverables can have primary owners without admitting invented paths', () => { + const root = repositoryFixture(); + mkdirSync(join(root, 'schemas')); + writeFileSync(join(root, 'schemas', 'contract.json'), '{"type":"object"}\n'); + writeFileSync(join(root, 'package.json'), '{"name":"ownership-fixture"}\n'); + execFileSync('git', ['-C', root, 'add', '.']); + execFileSync('git', ['-C', root, 'commit', '-m', 'observed non-code deliverables']); + const repository = inspectRepository(root); + const analysis = analyzeRepository(repository); + const baseline = proposeDomains({ repository, analysis }); + const brief = createFleetDesignBrief({ repository, analysis, baseline }); + const proposal = structuredClone(baseline); + proposal.domains[0].owned_paths = ['README.md', 'package.json', 'schemas/contract.json']; + proposal.domains[0].evidence = [...proposal.domains[0].owned_paths]; + proposal.organization_assessment = flatOrganizationAssessment(proposal); + assert.equal(validateArchitectProposal({ brief, proposal }).valid, true); + assert.equal(analysis.inventory.ownershipPathsTruncated, false); + for (const invented of ['schemas/missing.json', '../outside.json', 'schemas/**']) { + const invalid = structuredClone(proposal); + invalid.domains[0].owned_paths.push(invented); + invalid.domains[0].evidence.push(invented); + const result = validateArchitectProposal({ brief, proposal: invalid }); + assert.equal(result.valid, false); + assert.ok(result.problems.some((problem) => problem.includes('invented owned path:'))); + assert.ok(result.problems.some((problem) => problem.includes('cited unknown evidence:'))); + } + for (let index = 0; index < 1001; index += 1) { + writeFileSync(join(root, 'schemas', `generated-${String(index).padStart(4, '0')}.json`), '{}\n'); + } + const largeAnalysis = analyzeRepository(inspectRepository(root)); + assert.equal(largeAnalysis.inventory.ownershipPaths.length, 1000); + assert.equal(largeAnalysis.inventory.ownershipPathsTruncated, true); + const largeBaseline = proposeDomains({ repository: inspectRepository(root), analysis: largeAnalysis }); + const largeBrief = createFleetDesignBrief({ repository: inspectRepository(root), analysis: largeAnalysis, baseline: largeBaseline }); + const largeProposal = structuredClone(largeBaseline); + largeProposal.organization_assessment = flatOrganizationAssessment(largeProposal); + assert.ok(validateArchitectProposal({ brief: largeBrief, proposal: largeProposal }).findings + .some((finding) => finding.code === 'OWNERSHIP_EVIDENCE_TRUNCATED')); +}); + test('SCN-bootstrap-primary-ownership: pending and approved rosters reject duplicate and recursive primary claims, not shared consultation', () => { const root = repositoryFixture(); for (const name of ['api', 'world']) {