naive-framework 0.0.0-stage → 0.2.0
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/AGENTS.md +62 -0
- package/LICENSE +21 -0
- package/README.md +37 -2
- package/docs/decisions/decisions.json +888 -0
- package/docs/ontology.json +796 -0
- package/docs/ontology.md +163 -0
- package/docs/reference/ROUTES.md +124 -0
- package/evidence/benchmarks/2026-10-27-golden.jev.after-catalog-fix.json +558 -0
- package/evidence/benchmarks/2026-10-27-golden.jev.json +501 -0
- package/evidence/benchmarks/2026-10-27-golden.reasoning-answers.json +177 -0
- package/evidence/benchmarks/JEV_VS_REASONING_MODEL_2026-10-27.md +68 -0
- package/evidence/capabilities/agent-capabilities.json +86 -0
- package/evidence/design-documents.registry.json +2896 -0
- package/evidence/evals/evals.json +25 -0
- package/evidence/evals/harness-evals.json +140 -0
- package/evidence/layer.json +51 -0
- package/evidence/skills/agent-capabilities/SKILL.md +35 -0
- package/evidence/skills/design-coverage/SKILL.md +57 -0
- package/evidence/skills/design-coverage/check.mjs +192 -0
- package/evidence/skills/design-coverage/scan.mjs +45 -0
- package/evidence/skills/fidelity-ladder-audit/SKILL.md +121 -0
- package/evidence/skills/fidelity-ladder-audit/ladder-census.mjs +180 -0
- package/evidence/skills/findability/SKILL.md +32 -0
- package/evidence/skills/findability/inventory.rb +41 -0
- package/evidence/skills/foreshadowing-audit/SKILL.md +183 -0
- package/evidence/skills/metrics-review/SKILL.md +177 -0
- package/evidence/tooling/integrations.json +153 -0
- package/governance/layer.json +102 -0
- package/governance/references/references.json +26 -0
- package/governance/skills/board-design/SKILL.md +68 -0
- package/governance/skills/brand-pillar/SKILL.md +90 -0
- package/governance/skills/business-pillar/SKILL.md +96 -0
- package/governance/skills/chief-of-staff/SKILL.md +45 -0
- package/governance/skills/cofounder-structure/SKILL.md +64 -0
- package/governance/skills/cross-pillar-tradeoff/SKILL.md +168 -0
- package/governance/skills/equity-and-share-classes/SKILL.md +68 -0
- package/governance/skills/executive-roles/SKILL.md +95 -0
- package/governance/skills/exit-planning/SKILL.md +66 -0
- package/governance/skills/financing-and-investor-rights/SKILL.md +73 -0
- package/governance/skills/office-hours-mode/SKILL.md +113 -0
- package/governance/skills/product-pillar/SKILL.md +81 -0
- package/governance/skills/publication-policy/SKILL.md +63 -0
- package/governance/skills/role-and-candidate-authoring/SKILL.md +198 -0
- package/governance/skills/stakeholder-update/SKILL.md +177 -0
- package/governance/tooling/integrations.json +37 -0
- package/governance/venture-template/AGENT_ROLES_AND_DECISION_RIGHTS.md +58 -0
- package/governance/venture-template/COMPANY_VAULT_DEFINITION_2026-10-25.md +204 -0
- package/governance/venture-template/README.md +74 -0
- package/governance/venture-template/decision-rights.json +186 -0
- package/governance/venture-template/index.md +151 -0
- package/governance/venture-template/pillars/brand.md +209 -0
- package/governance/venture-template/pillars/business.md +255 -0
- package/governance/venture-template/pillars/product.md +254 -0
- package/governance/venture-template/render-roles.py +11 -0
- package/governance/venture-template/roles/README.md +85 -0
- package/governance/venture-template/roles/agent-roles.json +202 -0
- package/governance/venture-template/roles/ceo.md +163 -0
- package/governance/venture-template/roles/chief-of-staff.md +153 -0
- package/governance/venture-template/roles/cmo.md +165 -0
- package/governance/venture-template/roles/coo.md +189 -0
- package/governance/venture-template/roles/cto.md +158 -0
- package/governance/venture-template/roles/department-head.md +47 -0
- package/governance/venture-template/roles/forward-deployed-engineer.md +51 -0
- package/governance/venture-template/roles/founder.md +173 -0
- package/governance/venture-template/roles/hr-manager.md +49 -0
- package/governance/venture-template/roles/talent-acquisition-manager.md +50 -0
- package/governance/venture-template/roles/venture-roles.json +62 -0
- package/interface/acting.mjs +83 -0
- package/interface/adapters/claude-code.json +16 -0
- package/interface/adapters/codex.json +14 -0
- package/interface/adapters/cursor.json +16 -0
- package/interface/adapters.mjs +182 -0
- package/interface/api/server.mjs +71 -0
- package/interface/boundaries.mjs +218 -0
- package/interface/brand.mjs +214 -0
- package/interface/cli/find-venture.mjs +15 -0
- package/interface/cli/freshness.mjs +59 -0
- package/interface/cli/guard.mjs +6 -0
- package/interface/cli/mentura.mjs +341 -0
- package/interface/cli/naive.mjs +194 -0
- package/interface/context.mjs +524 -0
- package/interface/demo/board.mjs +581 -0
- package/interface/demo/decision-harness.mjs +91 -0
- package/interface/demo/live-agent.mjs +47 -0
- package/interface/dev/setup.mjs +84 -0
- package/interface/gate-hooks.mjs +36 -0
- package/interface/harness/evals.mjs +90 -0
- package/interface/harness/examples/pt-no-shows.dump.md +19 -0
- package/interface/harness/run.mjs +313 -0
- package/interface/harness/site.mjs +59 -0
- package/interface/instrumentation.mjs +86 -0
- package/interface/kit-boundary.mjs +73 -0
- package/interface/layer.json +37 -0
- package/interface/mcp/server.mjs +162 -0
- package/interface/operator-console/README.md +58 -0
- package/interface/package-routes.mjs +196 -0
- package/interface/provenance.mjs +65 -0
- package/interface/reads.mjs +173 -0
- package/interface/references/references.json +28 -0
- package/interface/release-card.mjs +42 -0
- package/interface/route-aliases.json +32 -0
- package/interface/router.mjs +653 -0
- package/interface/skills/install-mentura/SKILL.md +88 -0
- package/interface/skills/naive-setup/SKILL.md +71 -0
- package/interface/skills/naive-setup/artifact.html +83 -0
- package/interface/tooling/integrations.json +112 -0
- package/interface/vitals.mjs +115 -0
- package/interface/writes.mjs +190 -0
- package/knowledge/connectors/README.md +54 -0
- package/knowledge/connectors/catalog.mjs +118 -0
- package/knowledge/connectors/contract.mjs +56 -0
- package/knowledge/connectors/eval.mjs +176 -0
- package/knowledge/connectors/filesystem.mjs +79 -0
- package/knowledge/connectors/index.mjs +102 -0
- package/knowledge/connectors/resolve.mjs +44 -0
- package/knowledge/connectors/suite.mjs +80 -0
- package/knowledge/freshness.json +85 -0
- package/knowledge/layer.json +50 -0
- package/knowledge/skills/find-reference/SKILL.md +38 -0
- package/knowledge/skills/industry-awareness/SKILL.md +277 -0
- package/knowledge/templates/glossary.md +23 -0
- package/knowledge/tooling/integrations.json +127 -0
- package/knowledge/tooling/questions.md +46 -0
- package/operations/FOUNDER_OPERATING_MODEL_CAMPAIGN_2026-10-14.md +16 -0
- package/operations/departments.json +162 -0
- package/operations/handoff-v2.md +93 -0
- package/operations/layer.json +67 -0
- package/operations/marketing/check-public.mjs +68 -0
- package/operations/marketing/site/README.md +86 -0
- package/operations/marketing/site/matrix.json +731 -0
- package/operations/marketing/site/plan.mjs +117 -0
- package/operations/marketing/site/presence.mjs +252 -0
- package/operations/references/references.json +45 -0
- package/operations/skills/recruiting/SKILL.md +32 -0
- package/operations/skills/team-design/SKILL.md +36 -0
- package/operations/skills/tool-selection/SKILL.md +46 -0
- package/operations/templates/marketing-brand.md +46 -0
- package/operations/templates/public-assets.md +39 -0
- package/operations/templates/recruiting-brief.md +35 -0
- package/operations/tooling/integrations.json +158 -0
- package/package.json +59 -4
- package/packages/catalog.json +280 -0
- package/packages/cofounder/package.json +42 -0
- package/packages/counsel/package.json +47 -0
- package/packages/customers/package.json +41 -0
- package/packages/deals/package.json +27 -0
- package/packages/decisions/package.json +28 -0
- package/packages/engineering/package.json +41 -0
- package/packages/evidence/package.json +17 -0
- package/packages/finance/frames/fund-without-ceding-control.frame.json +177 -0
- package/packages/finance/package.json +48 -0
- package/packages/foundation/package.json +59 -0
- package/packages/fund/package.json +48 -0
- package/packages/investor/package.json +57 -0
- package/packages/investors/package.json +21 -0
- package/packages/legal/package.json +73 -0
- package/packages/marketing/package.json +63 -0
- package/packages/money/package.json +42 -0
- package/packages/operations/package.json +74 -0
- package/packages/partner/package.json +38 -0
- package/packages/people/package.json +64 -0
- package/packages/product/package.json +49 -0
- package/packages/raw/package.json +19 -0
- package/packages/relationships/package.json +52 -0
- package/packages/validation/package.json +112 -0
- package/platform/README.md +51 -0
- package/platform/adapter.json +15 -0
- package/platform/connectors/eval.mjs +154 -0
- package/platform/connectors/fake-github.mjs +91 -0
- package/platform/connectors/github.mjs +105 -0
- package/platform/integrations/jev.mjs +30 -0
- package/platform/integrations/langsmith-docket.mjs +53 -0
- package/platform/integrations/langsmith-setup.mjs +115 -0
- package/platform/integrations/langsmith.mjs +47 -0
- package/platform/integrations/remote-image.mjs +79 -0
- package/platform/integrations/rho.mjs +146 -0
- package/platform/integrations/site.mjs +75 -0
- package/platform/kits/README.md +14 -0
- package/platform/kits/agent-upgrade/kit.json +15 -0
- package/platform/kits/agent-upgrade/run.mjs +82 -0
- package/platform/kits/agent-upgrade/stand-in-agent.mjs +32 -0
- package/platform/kits/validation-kickoff/kit.json +29 -0
- package/platform/mcp/research.mjs +64 -0
- package/platform/webhooks/server.mjs +70 -0
- package/purpose/checklists/vault-and-tooling-consultancy-setup.md +216 -0
- package/purpose/frameworks/business-discovery-framework-amendments-2026-05-20.md +181 -0
- package/purpose/frameworks/business-discovery-framework.html +938 -0
- package/purpose/frameworks/business-discovery-framework.md +326 -0
- package/purpose/frameworks/idea-map/README.md +74 -0
- package/purpose/frameworks/idea-map/conventions.json +146 -0
- package/purpose/frameworks/idea-map/graph.mjs +182 -0
- package/purpose/frameworks/idea-map/ideamap.mjs +181 -0
- package/purpose/frameworks/idea-map/route.mjs +140 -0
- package/purpose/frameworks/onboarding-handoff-framework.md +269 -0
- package/purpose/frameworks/post-discovery-deliverable-playbook.md +274 -0
- package/purpose/frameworks/product-anatomy/README.md +63 -0
- package/purpose/frameworks/product-anatomy/anatomy.mjs +195 -0
- package/purpose/frameworks/product-anatomy/examples/polity.answers.reasoned.json +11 -0
- package/purpose/frameworks/product-anatomy/examples/polity.json +89 -0
- package/purpose/frameworks/product-anatomy/phases.json +107 -0
- package/purpose/frameworks/product-anatomy/questions.json +74 -0
- package/purpose/kits/validation/README.md +14 -0
- package/purpose/kits/validation/references/references.json +122 -0
- package/purpose/kits/validation/skills/problem-validation/SKILL.md +43 -0
- package/purpose/kits/validation/skills/validation-score/SKILL.md +35 -0
- package/purpose/kits/validation/templates/go-to-market.md +19 -0
- package/purpose/kits/validation/templates/operations-readiness.md +20 -0
- package/purpose/kits/validation/templates/pricing.md +22 -0
- package/purpose/kits/validation/templates/problem-interview.md +36 -0
- package/purpose/kits/validation/templates/problem.md +45 -0
- package/purpose/kits/validation/templates/product-market-fit.md +23 -0
- package/purpose/kits/validation/templates/solution.md +18 -0
- package/purpose/kits/validation/templates/team.md +19 -0
- package/purpose/kits/validation/weights.json +22 -0
- package/purpose/layer.json +53 -0
- package/purpose/references/references.json +324 -0
- package/purpose/skills/ambition-tier/SKILL.md +205 -0
- package/purpose/skills/telos/SKILL.md +52 -0
- package/purpose/strategic-foundation.json +133 -0
- package/purpose/templates/telos-based-smart.md +39 -0
- package/purpose/tooling/integrations.json +48 -0
- package/schema/README.md +62 -0
- package/schema/VERSION +1 -0
- package/schema/access.mjs +57 -0
- package/schema/account.schema.json +79 -0
- package/schema/adapter.schema.json +33 -0
- package/schema/add-department.mjs +41 -0
- package/schema/agent-capability.schema.json +94 -0
- package/schema/alignment.schema.json +61 -0
- package/schema/assess-problem.mjs +131 -0
- package/schema/assets.mjs +212 -0
- package/schema/bdd.mjs +56 -0
- package/schema/board.schema.json +101 -0
- package/schema/brand.mjs +373 -0
- package/schema/build-release.mjs +61 -0
- package/schema/caching.mjs +505 -0
- package/schema/check-assets.mjs +24 -0
- package/schema/check-boundary.mjs +54 -0
- package/schema/check-brand.mjs +24 -0
- package/schema/check-config.mjs +110 -0
- package/schema/check-data-model.mjs +170 -0
- package/schema/check-data-packages.mjs +83 -0
- package/schema/check-departments.mjs +45 -0
- package/schema/check-execution.mjs +85 -0
- package/schema/check-governance.mjs +98 -0
- package/schema/check-integrations.mjs +33 -0
- package/schema/check-nextjs-status.mjs +79 -0
- package/schema/check-nouns.mjs +49 -0
- package/schema/check-people.mjs +70 -0
- package/schema/check-private.mjs +61 -0
- package/schema/check-provenance.mjs +55 -0
- package/schema/check-publication.mjs +96 -0
- package/schema/check-ready.mjs +89 -0
- package/schema/check-sources.mjs +74 -0
- package/schema/check-team.mjs +94 -0
- package/schema/check-telos.mjs +59 -0
- package/schema/check-validation.mjs +165 -0
- package/schema/check-ventures.mjs +81 -0
- package/schema/check-where-used.mjs +58 -0
- package/schema/data-master.schema.json +14 -0
- package/schema/data-model.json +1584 -0
- package/schema/data-model.schema.json +152 -0
- package/schema/deal.schema.json +80 -0
- package/schema/decision-analytics.mjs +77 -0
- package/schema/decision-record.schema.json +290 -0
- package/schema/decision-rights.schema.json +34 -0
- package/schema/decision.schema.json +30 -0
- package/schema/decisions.mjs +327 -0
- package/schema/department-catalog.schema.json +55 -0
- package/schema/department.schema.json +15 -0
- package/schema/departments.mjs +32 -0
- package/schema/docket-eval.mjs +89 -0
- package/schema/docket.mjs +135 -0
- package/schema/eval-suite.schema.json +45 -0
- package/schema/evidence.schema.json +110 -0
- package/schema/examples/frames/judge.mjs +10 -0
- package/schema/examples/migrate/agent.mjs +12 -0
- package/schema/examples/venture-type/jev.mjs +12 -0
- package/schema/examples/workspace/ventures/acme-labs/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/acme-labs/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/discovery-goal.decision.json +23 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/statement-icp.decision.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/statement-problem.decision.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/venture.team.decision.json +37 -0
- package/schema/examples/workspace/ventures/acme-labs/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/acme-labs/knowledge/sources.json +46 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000001.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000002.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000003.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000004.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000005.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000006.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000007.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000008.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000009.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000010.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000011.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000012.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000013.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000014.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/_streams/transactions/stream.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/money/_summary.json +30 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/people/founders/maya-chen.json +15 -0
- package/schema/examples/workspace/ventures/acme-labs/people/people.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.core-product.decision.json +28 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.exists.decision.json +38 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.flagship.decision.json +27 -0
- package/schema/examples/workspace/ventures/acme-labs/profile.md +12 -0
- package/schema/examples/workspace/ventures/acme-labs/provenance.jsonl +12 -0
- package/schema/examples/workspace/ventures/acme-labs/raw/dump.md +6 -0
- package/schema/examples/workspace/ventures/acme-labs/venture.json +27 -0
- package/schema/examples/workspace/ventures/northstar/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/northstar/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/deals/ductline.json +8 -0
- package/schema/examples/workspace/ventures/northstar/deals/kilnworks.json +14 -0
- package/schema/examples/workspace/ventures/northstar/decisions/venture.team.decision.json +31 -0
- package/schema/examples/workspace/ventures/northstar/evidence/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.first-close.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/thesis.decision.json +26 -0
- package/schema/examples/workspace/ventures/northstar/fund/terms.json +22 -0
- package/schema/examples/workspace/ventures/northstar/fund/thesis.json +22 -0
- package/schema/examples/workspace/ventures/northstar/governance/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/finance/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/operations/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/people/founders/ana-ruiz.json +13 -0
- package/schema/examples/workspace/ventures/northstar/people/founders/ben-okafor.json +7 -0
- package/schema/examples/workspace/ventures/northstar/people/people.json +27 -0
- package/schema/examples/workspace/ventures/northstar/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/northstar/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/northstar/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/decisions/venture.team.decision.json +31 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.core-product.decision.json +28 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.exists.decision.json +32 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.flagship.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/profile.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/venture.json +27 -0
- package/schema/examples/workspace/ventures/northstar/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/profile.md +5 -0
- package/schema/examples/workspace/ventures/northstar/provenance.jsonl +3 -0
- package/schema/examples/workspace/ventures/northstar/purpose/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/venture.json +49 -0
- package/schema/examples/workspace/ventures/studio/accounts/bakery/account.json +18 -0
- package/schema/examples/workspace/ventures/studio/evidence/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/governance/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/operations/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/purpose/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/venture.json +37 -0
- package/schema/examples/workspace/ventures/studio/products/brand-care.json +19 -0
- package/schema/examples/workspace/ventures/studio/products/brand-kit.json +23 -0
- package/schema/examples/workspace/ventures/studio/provenance.jsonl +3 -0
- package/schema/examples/workspace/ventures/studio/purpose/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/venture.json +43 -0
- package/schema/examples/workspace/ventures/tandem/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/tandem/evidence/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/agreements/dee-fast.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/board.json +51 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/finance/charter.md +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/charter.md +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/exit.json +33 -0
- package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.json +24 -0
- package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/ownership.json +131 -0
- package/schema/examples/workspace/ventures/tandem/governance/publication-policy.json +171 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/friends-feedback-2026-08.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/pilot-2026-10.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/problem-interviews-2026-09.md +20 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/sources.json +8 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/where-used.json +13 -0
- package/schema/examples/workspace/ventures/tandem/operations/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/tandem/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/tandem/products/shop-app.json +22 -0
- package/schema/examples/workspace/ventures/tandem/profile.md +5 -0
- package/schema/examples/workspace/ventures/tandem/provenance.jsonl +13 -0
- package/schema/examples/workspace/ventures/tandem/purpose/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/purpose/telos.json +78 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/go-to-market.json +35 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/pricing.json +37 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/problem.json +74 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/product-market-fit.json +66 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/solution.json +33 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/team.json +52 -0
- package/schema/examples/workspace/ventures/tandem/venture.json +79 -0
- package/schema/examples/workspace/ventures/woodworking/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/woodworking/venture.json +21 -0
- package/schema/examples/workspace/workspace.json +8 -0
- package/schema/exit.schema.json +74 -0
- package/schema/foundation.mjs +118 -0
- package/schema/founder-agreement.schema.json +83 -0
- package/schema/founder.schema.json +72 -0
- package/schema/frame.schema.json +240 -0
- package/schema/frames.mjs +228 -0
- package/schema/freshness-log.schema.json +40 -0
- package/schema/freshness-profiles.schema.json +44 -0
- package/schema/freshness.mjs +473 -0
- package/schema/fund-terms.schema.json +107 -0
- package/schema/fund-thesis.schema.json +87 -0
- package/schema/gate-drafts.mjs +130 -0
- package/schema/gate.mjs +133 -0
- package/schema/glossary.schema.json +25 -0
- package/schema/handoff.schema.json +239 -0
- package/schema/icp.schema.json +136 -0
- package/schema/idea-graph.schema.json +61 -0
- package/schema/init-venture.mjs +128 -0
- package/schema/integration.schema.json +143 -0
- package/schema/judgment.schema.json +38 -0
- package/schema/kit.schema.json +47 -0
- package/schema/kits.mjs +24 -0
- package/schema/knowledge-sources.schema.json +260 -0
- package/schema/layer.json +59 -0
- package/schema/layer.schema.json +119 -0
- package/schema/load-packages.mjs +26 -0
- package/schema/marketing-brand.schema.json +116 -0
- package/schema/marketing-sitemap.schema.json +232 -0
- package/schema/migrate-venture.mjs +192 -0
- package/schema/migrations/kit-to-package.mjs +94 -0
- package/schema/migrations/package-layout.mjs +86 -0
- package/schema/model-steps.mjs +717 -0
- package/schema/money-summary.schema.json +138 -0
- package/schema/naive-config.mjs +165 -0
- package/schema/naive-config.schema.json +268 -0
- package/schema/need-now.json +772 -0
- package/schema/need-now.mjs +108 -0
- package/schema/nextjs-status.schema.json +29 -0
- package/schema/ownership.schema.json +282 -0
- package/schema/packages.json +4 -0
- package/schema/packages.mjs +252 -0
- package/schema/payouts.mjs +91 -0
- package/schema/people.schema.json +86 -0
- package/schema/port-venture.mjs +161 -0
- package/schema/product.schema.json +223 -0
- package/schema/provenance-entry.schema.json +154 -0
- package/schema/public-assets.schema.json +76 -0
- package/schema/publication-policy.schema.json +293 -0
- package/schema/raw-source.schema.json +15 -0
- package/schema/reference.schema.json +115 -0
- package/schema/release-read.mjs +111 -0
- package/schema/releases.mjs +497 -0
- package/schema/route-aliases.schema.json +25 -0
- package/schema/run-handoff.mjs +51 -0
- package/schema/scaffold/defaults.json +54 -0
- package/schema/setup.mjs +164 -0
- package/schema/site-presence.schema.json +337 -0
- package/schema/stale.mjs +111 -0
- package/schema/start-release.mjs +41 -0
- package/schema/strategic-foundation.schema.json +74 -0
- package/schema/stream.schema.json +14 -0
- package/schema/structure.mjs +186 -0
- package/schema/systems-catalog.json +126 -0
- package/schema/systems-catalog.schema.json +78 -0
- package/schema/team-plan.schema.json +157 -0
- package/schema/telos.schema.json +197 -0
- package/schema/time-to-ready.mjs +93 -0
- package/schema/trigger.schema.json +44 -0
- package/schema/triggers.mjs +237 -0
- package/schema/upgrade-registry.schema.json +60 -0
- package/schema/upgrade-venture.mjs +107 -0
- package/schema/upgrades.json +69 -0
- package/schema/upgrades.mjs +385 -0
- package/schema/use-model.mjs +10 -0
- package/schema/validate.py +58 -0
- package/schema/validation-evidence.schema.json +123 -0
- package/schema/validation-go-to-market.schema.json +110 -0
- package/schema/validation-operations-readiness.schema.json +91 -0
- package/schema/validation-pricing.schema.json +114 -0
- package/schema/validation-problem.schema.json +118 -0
- package/schema/validation-product-market-fit.schema.json +135 -0
- package/schema/validation-solution.schema.json +79 -0
- package/schema/validation-team.schema.json +116 -0
- package/schema/venture-role.schema.json +64 -0
- package/schema/venture-type.mjs +62 -0
- package/schema/venture-types.json +346 -0
- package/schema/venture-types.schema.json +129 -0
- package/schema/venture.schema.json +460 -0
- package/schema/vocab/business-models.json +298 -0
- package/schema/where-used.schema.json +56 -0
- package/schema/workspace.schema.json +38 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Checks docs/design/naive-nextjs-status.json against the Next.js translation ledger and the code: every
|
|
3
|
+
// concept row in the ledger has exactly one status; a built or partial row cites files that exist and a
|
|
4
|
+
// docs page that exists; and the generated "What's built" page matches the data.
|
|
5
|
+
//
|
|
6
|
+
// node schema/check-nextjs-status.mjs check, and print the counts
|
|
7
|
+
// node schema/check-nextjs-status.mjs --write write site/content/docs/get-started/whats-built.mdx
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
const repo = new URL("..", import.meta.url).pathname;
|
|
13
|
+
const LEDGER = "docs/design/NAIVE_NEXTJS_TRANSLATION_2026-10-28.md";
|
|
14
|
+
const STATUS = "docs/design/naive-nextjs-status.json";
|
|
15
|
+
const PAGE = "site/content/docs/get-started/whats-built.mdx";
|
|
16
|
+
const STATES = ["built", "partial", "not built", "n/a"];
|
|
17
|
+
|
|
18
|
+
const ids = [...readFileSync(join(repo, LEDGER), "utf8").matchAll(/^\| ([A-Z]-\d+) \|/gm)].map((m) => m[1]);
|
|
19
|
+
const data = JSON.parse(readFileSync(join(repo, STATUS), "utf8"));
|
|
20
|
+
const errors = [];
|
|
21
|
+
const seen = new Map();
|
|
22
|
+
for (const r of data.rows) {
|
|
23
|
+
if (seen.has(r.id)) errors.push(`${r.id} has two entries`);
|
|
24
|
+
seen.set(r.id, r);
|
|
25
|
+
if (!ids.includes(r.id)) errors.push(`${r.id} is not a row of the ledger`);
|
|
26
|
+
if (!STATES.includes(r.status)) errors.push(`${r.id}: status ${r.status} is not one of ${STATES.join(", ")}`);
|
|
27
|
+
if (r.status === "built" || r.status === "partial") {
|
|
28
|
+
if (!r.evidence?.length) errors.push(`${r.id} is ${r.status} but cites no file`);
|
|
29
|
+
for (const f of r.evidence ?? []) if (!existsSync(join(repo, f))) errors.push(`${r.id} cites ${f}, which does not exist`);
|
|
30
|
+
if (!r.page) errors.push(`${r.id} is ${r.status} but names no docs page`);
|
|
31
|
+
else if (!existsSync(join(repo, "site/content/docs", `${r.page}.mdx`))) errors.push(`${r.id} names page ${r.page}, which does not exist`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const id of ids) if (!seen.has(id)) errors.push(`${id} is in the ledger but has no status`);
|
|
35
|
+
|
|
36
|
+
const count = (s) => data.rows.filter((r) => r.status === s).length;
|
|
37
|
+
const counts = Object.fromEntries(STATES.map((s) => [s, count(s)]));
|
|
38
|
+
|
|
39
|
+
function page() {
|
|
40
|
+
const chapters = [...new Set(data.rows.map((r) => r.chapter))];
|
|
41
|
+
// MDX reads { and < as code outside backticks, so they are escaped there.
|
|
42
|
+
const mdx = (t) => t.split(/(`[^`]*`)/).map((x, i) => i % 2 ? x : x.replace(/[{}]/g, (c) => `\\${c}`).replace(/</g, "<").replace(/>/g, ">")).join("");
|
|
43
|
+
const cell = (s) => mdx(String(s ?? "")).replace(/\|/g, "\\|");
|
|
44
|
+
const lines = [
|
|
45
|
+
"---",
|
|
46
|
+
"title: What's built",
|
|
47
|
+
"description: Which of the 234 concepts translated from Next.js work today, which partly work, and which are design only.",
|
|
48
|
+
"type: reference",
|
|
49
|
+
"status: draft",
|
|
50
|
+
`lastReviewed: ${data.checked}`,
|
|
51
|
+
"owner: builder",
|
|
52
|
+
"---",
|
|
53
|
+
"",
|
|
54
|
+
`Use this page to tell what you can run today from what is designed but not built. Every concept in the Next.js translation ledger is listed, in the ledger's chapter order. It is generated from \`${STATUS}\` by \`node schema/check-nextjs-status.mjs --write\`, and the test suite fails when the two disagree.`,
|
|
55
|
+
"",
|
|
56
|
+
"## Summary",
|
|
57
|
+
"",
|
|
58
|
+
"| Status | Concepts | Meaning |",
|
|
59
|
+
"| --- | --- | --- |",
|
|
60
|
+
`| built | ${counts.built} | Works end to end and is tested |`,
|
|
61
|
+
`| partial | ${counts.partial} | Some of it works; the note says what is missing |`,
|
|
62
|
+
`| not built | ${counts["not built"]} | Designed in the ledger, not in the code yet |`,
|
|
63
|
+
`| n/a | ${counts["n/a"]} | The ledger marks it as not converting from Next.js |`,
|
|
64
|
+
"",
|
|
65
|
+
];
|
|
66
|
+
for (const c of chapters) {
|
|
67
|
+
const rows = data.rows.filter((r) => r.chapter === c);
|
|
68
|
+
lines.push(`## ${c.replace(/^Chapter \d+: /, "")}`, "", "| Concept | Status | Explained in | Note |", "| --- | --- | --- | --- |");
|
|
69
|
+
for (const r of rows) lines.push(`| ${r.id} | ${r.status} | ${r.page && r.page !== "get-started/whats-built" ? `[${r.page.split("/").at(-1)}](/docs/${r.page})` : ""} | ${cell(r.note)} |`);
|
|
70
|
+
lines.push("");
|
|
71
|
+
}
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (process.argv.includes("--write")) { writeFileSync(join(repo, PAGE), page()); console.log(`wrote ${PAGE}`); }
|
|
76
|
+
else if (!existsSync(join(repo, PAGE)) || readFileSync(join(repo, PAGE), "utf8") !== page()) errors.push(`${PAGE} is out of date: run node schema/check-nextjs-status.mjs --write`);
|
|
77
|
+
|
|
78
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
79
|
+
console.log(`${data.rows.length} concepts: ${STATES.map((s) => `${counts[s]} ${s}`).join(", ")}`);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Checks the system's nouns (EE-014). Fails when a retired noun from docs/ontology.json
|
|
2
|
+
// reappears in the checked files, or when a noun cites a reference id that no layer's
|
|
3
|
+
// references/references.json holds. With --md, prints the glossary as Markdown instead.
|
|
4
|
+
//
|
|
5
|
+
// node schema/check-nouns.mjs check
|
|
6
|
+
// node schema/check-nouns.mjs --md print docs/ontology.md's glossary tables
|
|
7
|
+
//
|
|
8
|
+
// A line that names a retired noun on purpose (to say what replaced it) carries "(was"
|
|
9
|
+
// or "retired" and is skipped.
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
// EE_ROOT points the check at another copy of the repository (used by schema/test.mjs).
|
|
15
|
+
const root = process.env.EE_ROOT?.replace(/\/?$/, "/") ?? new URL("..", import.meta.url).pathname;
|
|
16
|
+
const { check, nouns } = JSON.parse(readFileSync(join(root, "docs/ontology.json"), "utf8"));
|
|
17
|
+
|
|
18
|
+
if (process.argv.includes("--md")) {
|
|
19
|
+
const row = (n) => `| ${n.noun} | ${n.meaning} | ${n.standard} | ${(n.references ?? []).join(", ")} |`;
|
|
20
|
+
for (const level of [...new Set(nouns.filter((n) => n.status !== "retired").map((n) => n.level))]) {
|
|
21
|
+
console.log(`\n### ${level[0].toUpperCase() + level.slice(1)}\n\n| Noun | Meaning | Standard | References |\n| --- | --- | --- | --- |`);
|
|
22
|
+
nouns.filter((n) => n.level === level && n.status !== "retired").forEach((n) => console.log(row(n)));
|
|
23
|
+
}
|
|
24
|
+
console.log(`\n### Retired\n\n| Noun | Status |\n| --- | --- |`);
|
|
25
|
+
nouns.filter((n) => n.status === "retired").forEach((n) => console.log(`| ${n.noun} | retired; use ${n.replaced_by} |`));
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const walk = (p) => statSync(p).isDirectory()
|
|
30
|
+
? readdirSync(p).flatMap((e) => walk(join(p, e)))
|
|
31
|
+
: /\.(mdx?|json|mjs)$/.test(p) ? [p] : [];
|
|
32
|
+
const files = check.map((c) => join(root, c)).filter(existsSync).flatMap(walk)
|
|
33
|
+
.filter((f) => !f.endsWith("docs/ontology.json") && !f.endsWith("check-nouns.mjs"));
|
|
34
|
+
const errors = [];
|
|
35
|
+
for (const n of nouns.filter((x) => x.retired_pattern)) {
|
|
36
|
+
const re = new RegExp(n.retired_pattern, "i");
|
|
37
|
+
for (const f of files) readFileSync(f, "utf8").split("\n").forEach((line, i) => {
|
|
38
|
+
if (re.test(line) && !/\(was|retired/i.test(line)) errors.push(`${f.slice(root.length)}:${i + 1}: retired noun "${n.noun}" (use ${n.replaced_by})`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Layer references, and those of any kit inside a layer (<layer>/kits/<kit>/references).
|
|
42
|
+
const refFiles = readdirSync(root).flatMap((d) => [join(d, "references/references.json"),
|
|
43
|
+
...(existsSync(join(root, d, "kits")) ? readdirSync(join(root, d, "kits")).map((k) => join(d, "kits", k, "references/references.json")) : [])]);
|
|
44
|
+
const known = new Set(refFiles.filter((f) => existsSync(join(root, f)))
|
|
45
|
+
.flatMap((f) => JSON.parse(readFileSync(join(root, f), "utf8")).references.map((r) => r.id)));
|
|
46
|
+
for (const n of nouns) for (const r of n.references ?? []) if (!known.has(r)) errors.push(`docs/ontology.json: ${n.noun} cites unknown reference ${r}`);
|
|
47
|
+
|
|
48
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
49
|
+
console.log(`${nouns.length} nouns (${nouns.filter((n) => n.status === "retired").length} retired), ${files.length} files checked: no retired noun in use, every reference resolves.`);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Checks venture types and people (EE-082) in a workspace: a venture's type is in schema/venture-types.json;
|
|
3
|
+
// in people/people.json every role is in the role registry and allowed for the venture's type, every hat
|
|
4
|
+
// is a function the venture imports, a solo venture has one person who wears every hat, and every
|
|
5
|
+
// founder has a file in people/founders/ that agrees with the roster (and the roster lists every file).
|
|
6
|
+
//
|
|
7
|
+
// node schema/check-people.mjs <workspace>
|
|
8
|
+
|
|
9
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { roles as ROLES, types as TYPES } from "./venture-type.mjs";
|
|
12
|
+
|
|
13
|
+
const ws = process.argv[2];
|
|
14
|
+
if (!ws || !existsSync(ws)) { console.error("usage: node schema/check-people.mjs <workspace>"); process.exit(2); }
|
|
15
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
16
|
+
const walk = (d) => readdirSync(d, { withFileTypes: true }).flatMap((e) => e.name === "node_modules" || e.name.startsWith(".") ? []
|
|
17
|
+
: e.isDirectory() ? walk(join(d, e.name)) : e.name === "venture.json" ? [d] : []);
|
|
18
|
+
|
|
19
|
+
const types = new Map(TYPES().map((t) => [t.id, t]));
|
|
20
|
+
const roles = new Map(ROLES().map((r) => [r.id, r]));
|
|
21
|
+
const errors = [];
|
|
22
|
+
let ventures = 0, rosters = 0;
|
|
23
|
+
for (const dir of walk(ws)) {
|
|
24
|
+
ventures++;
|
|
25
|
+
const v = load(join(dir, "venture.json"));
|
|
26
|
+
const at = (m) => errors.push(`${v.id}: ${m}`);
|
|
27
|
+
const type = v.type ? types.get(v.type) : null;
|
|
28
|
+
if (v.type && !type) at(`type ${v.type} is not in schema/venture-types.json`);
|
|
29
|
+
const rosterFile = join(dir, "people/people.json");
|
|
30
|
+
const fdir = join(dir, "people/founders");
|
|
31
|
+
const files = existsSync(fdir) ? readdirSync(fdir).filter((f) => f.endsWith(".json")) : [];
|
|
32
|
+
if (!existsSync(rosterFile)) { if (files.length) at("people/founders/ has files but there is no people/people.json"); continue; }
|
|
33
|
+
rosters++;
|
|
34
|
+
const roster = load(rosterFile);
|
|
35
|
+
const imported = new Set(v.departments ?? []);
|
|
36
|
+
for (const p of roster.people) {
|
|
37
|
+
const role = roles.get(p.role);
|
|
38
|
+
if (!role) { at(`${p.id} has role ${p.role}, which is not in governance/venture-template/roles/venture-roles.json`); continue; }
|
|
39
|
+
if (type && !type.roles.includes(p.role)) at(`${p.id} is a ${p.role}, which a ${type.label.toLowerCase()} does not have (${type.roles.join(", ")})`);
|
|
40
|
+
for (const h of p.hats) if (imported.size && !imported.has(h)) at(`${p.id} wears the ${h} hat, but venture.json does not import ${h}`);
|
|
41
|
+
if (!role.owns_when_solo && p.hats.length) at(`${p.id} is a ${p.role}, who owns no function, but wears ${p.hats.join(", ")}`);
|
|
42
|
+
if (role.founder) {
|
|
43
|
+
const f = `people/founders/${p.id}.json`;
|
|
44
|
+
if (p.founder_file !== f) at(`${p.id} is a founder, so founder_file is ${f}`);
|
|
45
|
+
else if (!existsSync(join(dir, f))) at(`${f} is missing`);
|
|
46
|
+
else {
|
|
47
|
+
const rec = load(join(dir, f));
|
|
48
|
+
if (rec.id !== p.id || rec.role !== p.role) at(`${f} says ${rec.id} is a ${rec.role}; the roster says ${p.id} is a ${p.role}`);
|
|
49
|
+
if (JSON.stringify([...rec.hats].sort()) !== JSON.stringify([...p.hats].sort())) at(`${f} and the roster disagree on ${p.id}'s hats`);
|
|
50
|
+
if (rec.agreement && !existsSync(join(dir, rec.agreement.path))) at(`${f} links a founder agreement at ${rec.agreement.path}, which does not exist`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (roster.mode === "solo") {
|
|
55
|
+
if (roster.people.length !== 1) at(`a solo venture has one person; people/people.json lists ${roster.people.length}`);
|
|
56
|
+
else if (roles.get(roster.people[0].role)?.owns_when_solo && imported.size) {
|
|
57
|
+
const missing = [...imported].filter((h) => !roster.people[0].hats.includes(h));
|
|
58
|
+
if (missing.length) at(`${roster.people[0].id} is alone, so owns every function; missing ${missing.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (roster.mode === "team" && imported.size) {
|
|
62
|
+
const worn = new Set(roster.people.flatMap((p) => p.hats));
|
|
63
|
+
const unowned = [...imported].filter((h) => !worn.has(h));
|
|
64
|
+
if (unowned.length) at(`no one owns ${unowned.join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
for (const f of files) if (!roster.people.some((p) => p.founder_file === `people/founders/${f}`)) at(`people/founders/${f} is not in people/people.json`);
|
|
67
|
+
}
|
|
68
|
+
for (const e of errors) console.log(`FAIL ${e}`);
|
|
69
|
+
console.log(`${ventures} ventures, ${rosters} people rosters: ${errors.length ? `${errors.length} error(s)` : "every role, hat and founder file agrees"}.`);
|
|
70
|
+
process.exit(errors.length ? 1 : 0);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Private records, fields, and sensitive streams never reach a model (EE-073).
|
|
3
|
+
// Fails when a private target is named in a package use_model step's inputs, or when
|
|
4
|
+
// a private record sits in a release that a package with use_model would read.
|
|
5
|
+
//
|
|
6
|
+
// node schema/check-private.mjs <venture dir>
|
|
7
|
+
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
const dir = process.argv[2];
|
|
12
|
+
if (!dir) { console.error("usage: node schema/check-private.mjs <venture dir>"); process.exit(2); }
|
|
13
|
+
const repo = process.env.EE_ROOT?.replace(/\/?$/, "/") ?? new URL("..", import.meta.url).pathname;
|
|
14
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
15
|
+
|
|
16
|
+
const packages = readdirSync(join(repo, "packages")).flatMap((name) => {
|
|
17
|
+
const p = join(repo, "packages", name, "package.json");
|
|
18
|
+
return existsSync(p) ? [load(p)] : [];
|
|
19
|
+
});
|
|
20
|
+
const inputs = packages.flatMap((pkg) => (pkg.use_model ?? []).flatMap((step) => {
|
|
21
|
+
if (typeof step === "string") return [{ package: pkg.name, input: step }];
|
|
22
|
+
return (step.inputs ?? []).map((input) => ({ package: pkg.name, input }));
|
|
23
|
+
}));
|
|
24
|
+
const readsRelease = packages.some((pkg) => (pkg.use_model ?? []).length > 0);
|
|
25
|
+
|
|
26
|
+
function walk(d) {
|
|
27
|
+
if (!existsSync(d)) return [];
|
|
28
|
+
return readdirSync(d, { withFileTypes: true }).flatMap((e) => {
|
|
29
|
+
if (e.name === "node_modules" || e.name === ".git") return [];
|
|
30
|
+
const p = join(d, e.name);
|
|
31
|
+
return e.isDirectory() ? walk(p) : [p];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const privateTargets = new Set();
|
|
36
|
+
const privateRecords = new Set();
|
|
37
|
+
for (const f of walk(dir).filter((p) => p.endsWith(".json"))) {
|
|
38
|
+
let rec;
|
|
39
|
+
try { rec = load(f); } catch { continue; }
|
|
40
|
+
if (!rec || typeof rec !== "object" || Array.isArray(rec)) continue;
|
|
41
|
+
const id = typeof rec.id === "string" ? rec.id : null;
|
|
42
|
+
if (rec.private === true && id) { privateTargets.add(id); privateRecords.add(id); }
|
|
43
|
+
for (const field of rec.private_fields ?? []) if (id) privateTargets.add(`${id}.${field}`);
|
|
44
|
+
if (rec.sensitive === true && id) privateTargets.add(id);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const errors = [];
|
|
48
|
+
for (const { package: name, input } of inputs) {
|
|
49
|
+
if (privateTargets.has(input) || privateRecords.has(input.split(".")[0])) errors.push(`${name}: use_model input ${input} is private and must not reach a model`);
|
|
50
|
+
}
|
|
51
|
+
if (readsRelease) {
|
|
52
|
+
const release = join(dir, ".release");
|
|
53
|
+
if (existsSync(release) && statSync(release).isDirectory()) {
|
|
54
|
+
for (const f of walk(release).filter((p) => p.endsWith(".json"))) {
|
|
55
|
+
const text = readFileSync(f, "utf8");
|
|
56
|
+
for (const id of privateRecords) if (text.includes(`"${id}"`)) errors.push(`.release mentions private record ${id}, and a package with use_model would read it`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
61
|
+
console.log(`${dir}: private records stay off the model.`);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Checks each venture's provenance log (<venture>/provenance.jsonl, EE-031).
|
|
2
|
+
// errors: a line that is not JSON; a broken chain (a line's prev is not the hash of the line
|
|
3
|
+
// before, or its hash does not match its content), which means a line was edited, removed or
|
|
4
|
+
// reordered; an entity outside the venture folder (a record in another source is logged by
|
|
5
|
+
// its address, <source>://<path>, and carries the source's version; EE-037).
|
|
6
|
+
// warnings: a logged file that has changed since its last entry, or is gone, so its later
|
|
7
|
+
// history is only in git; a derived_from path (not a URL or a decision id) that is not in the
|
|
8
|
+
// venture folder; time going backwards.
|
|
9
|
+
// The schema of each line is checked by schema/validate.py.
|
|
10
|
+
//
|
|
11
|
+
// node schema/check-provenance.mjs <workspace or venture dir>
|
|
12
|
+
|
|
13
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { contentHash, lineHash, LOG } from "../interface/provenance.mjs";
|
|
16
|
+
|
|
17
|
+
const dir = process.argv[2];
|
|
18
|
+
if (!dir) { console.error("usage: node schema/check-provenance.mjs <workspace or venture dir>"); process.exit(2); }
|
|
19
|
+
const walk = (d) => readdirSync(d, { withFileTypes: true }).flatMap((e) => e.name === "node_modules" || e.name.startsWith(".") ? []
|
|
20
|
+
: e.isDirectory() ? walk(join(d, e.name)) : e.name === "venture.json" ? [d] : []);
|
|
21
|
+
const errors = [], warnings = [];
|
|
22
|
+
let logs = 0, lines = 0;
|
|
23
|
+
|
|
24
|
+
for (const root of walk(dir)) {
|
|
25
|
+
const f = join(root, LOG);
|
|
26
|
+
if (!existsSync(f)) continue;
|
|
27
|
+
logs++;
|
|
28
|
+
const id = JSON.parse(readFileSync(join(root, "venture.json"), "utf8")).id;
|
|
29
|
+
let prev = "genesis", at = "";
|
|
30
|
+
const last = new Map();
|
|
31
|
+
readFileSync(f, "utf8").split("\n").forEach((l, i) => {
|
|
32
|
+
if (!l.trim()) return;
|
|
33
|
+
const where = `${id}/${LOG}:${i + 1}`;
|
|
34
|
+
let e;
|
|
35
|
+
try { e = JSON.parse(l); } catch { errors.push(`${where}: not JSON`); prev = null; return; }
|
|
36
|
+
lines++;
|
|
37
|
+
if (prev !== null && e.prev !== prev) errors.push(`${where}: chain broken: prev does not match the line before (a line was edited, removed or reordered)`);
|
|
38
|
+
if (e.hash !== lineHash(e.prev, e)) errors.push(`${where}: hash does not match the line's content (the line was edited)`);
|
|
39
|
+
if (/^\/|(^|\/)\.\.(\/|$)/.test(e.entity ?? "") || (/^[a-z][a-z0-9+.-]*:\/\//.test(e.entity ?? "") && !e.source)) errors.push(`${where}: entity ${e.entity} is outside the venture folder`);
|
|
40
|
+
if (e.at < at) warnings.push(`${where}: time goes backwards`);
|
|
41
|
+
at = e.at; prev = e.hash;
|
|
42
|
+
if (typeof e.entity !== "string") { errors.push(`${where}: no entity`); return; }
|
|
43
|
+
if (!e.source) last.set(e.entity, e);
|
|
44
|
+
for (const d of e.derived_from ?? []) if (!/^[a-z][a-z0-9+.-]*:\/\//.test(d) && !/^[A-Z]+-\d+$/.test(d) && !d.startsWith("_drafts/") && !existsSync(join(root, d))) warnings.push(`${where}: derived from ${d}, which is not in the venture folder`);
|
|
45
|
+
});
|
|
46
|
+
for (const [entity, e] of last) {
|
|
47
|
+
const p = join(root, entity);
|
|
48
|
+
if (!existsSync(p)) { if (e.activity !== "draft") warnings.push(`${id}: ${entity} is in the log but gone; git holds what happened`); continue; }
|
|
49
|
+
if (contentHash(p) !== e.sha256) warnings.push(`${id}: ${entity} changed outside the router since ${e.at}; git holds that history`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for (const w of warnings) console.warn(`warning: ${w}`);
|
|
54
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
55
|
+
console.log(`${logs} provenance logs, ${lines} entries: every chain holds.`);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Checks each venture's publication policy (governance/publication-policy.json, EE-025) and the
|
|
2
|
+
// handoffs that publish. Every publication passes the gate. Rules:
|
|
3
|
+
// policy: channel, guideline and team ids unique; a team's members are known roles; a channel's
|
|
4
|
+
// guidelines are known; a guideline or channel config named by path exists (paths are
|
|
5
|
+
// relative to the venture folder); an outside guideline with a URL states when it was
|
|
6
|
+
// checked (warning); a channel following no brand or editorial guideline is a warning.
|
|
7
|
+
// platforms: a channel on a platform cites a platform guideline; a social, newsletter or
|
|
8
|
+
// app-store channel names its platform.
|
|
9
|
+
// replies: a social, newsletter or blog channel says how replies and comments are handled;
|
|
10
|
+
// delegated replies go to known roles or teams that include a person, never to agents alone.
|
|
11
|
+
// rights: drafters and approvers are known roles or teams; no agent approves, and a team
|
|
12
|
+
// approves only if a person is among its members; every rule has a person approving.
|
|
13
|
+
// handoffs: a handoff that publishes (public-commitment in its decision classes or its
|
|
14
|
+
// escalations) names a channel and a content rule the policy holds; a venture with such a
|
|
15
|
+
// handoff and no policy fails.
|
|
16
|
+
//
|
|
17
|
+
// node schema/check-publication.mjs <workspace or venture dir>
|
|
18
|
+
|
|
19
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
|
|
22
|
+
const dir = process.argv[2];
|
|
23
|
+
if (!dir) { console.error("usage: node schema/check-publication.mjs <workspace or venture dir>"); process.exit(2); }
|
|
24
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
25
|
+
const walk = (d) => readdirSync(d, { withFileTypes: true }).flatMap((e) => e.name === "node_modules" || e.name.startsWith(".") ? []
|
|
26
|
+
: e.isDirectory() ? walk(join(d, e.name)) : e.name === "venture.json" ? [d] : []);
|
|
27
|
+
const roles = new Map(load(new URL("../governance/venture-template/roles/agent-roles.json", import.meta.url)).roles.map((r) => [r.id, r]));
|
|
28
|
+
const errors = [], warnings = [];
|
|
29
|
+
let checked = 0;
|
|
30
|
+
|
|
31
|
+
for (const root of walk(dir)) {
|
|
32
|
+
const v = load(join(root, "venture.json"));
|
|
33
|
+
const pPath = join(root, "governance/publication-policy.json");
|
|
34
|
+
const policy = existsSync(pPath) ? load(pPath) : null;
|
|
35
|
+
const at = `${v.id}/governance/publication-policy.json`;
|
|
36
|
+
const hDir = join(root, "operations/handoffs");
|
|
37
|
+
const handoffs = existsSync(hDir) ? readdirSync(hDir).filter((f) => f.endsWith(".json")).map((f) => [f, load(join(hDir, f))]) : [];
|
|
38
|
+
|
|
39
|
+
for (const [f, h] of handoffs) {
|
|
40
|
+
const publishes = (h.decision_classes ?? []).includes("public-commitment") || (h.escalations ?? []).some((e) => e.class === "public-commitment");
|
|
41
|
+
const where = `${v.id}/operations/handoffs/${f}`;
|
|
42
|
+
if (!publishes) { if (h.publication) warnings.push(`${where}: names a publication but has no public-commitment class`); continue; }
|
|
43
|
+
if (!policy) { errors.push(`${where}: publishes, but the venture has no governance/publication-policy.json`); continue; }
|
|
44
|
+
if (!h.publication) { errors.push(`${where}: publishes, so it names its channel and content (publication)`); continue; }
|
|
45
|
+
const ch = policy.channels.find((c) => c.id === h.publication.channel);
|
|
46
|
+
if (!ch) errors.push(`${where}: unknown channel ${h.publication.channel}`);
|
|
47
|
+
else if (!ch.rules.some((r) => r.content === h.publication.content)) errors.push(`${where}: channel ${ch.id} has no rule for "${h.publication.content}"`);
|
|
48
|
+
}
|
|
49
|
+
if (!policy) continue;
|
|
50
|
+
checked++;
|
|
51
|
+
|
|
52
|
+
const dup = (xs, what) => { const ids = xs.map((x) => x.id); if (new Set(ids).size !== ids.length) errors.push(`${at}: duplicate ${what} ids`); };
|
|
53
|
+
dup(policy.channels, "channel"); dup(policy.guidelines ?? [], "guideline"); dup(policy.teams ?? [], "team");
|
|
54
|
+
const teams = new Map((policy.teams ?? []).map((t) => [t.id, t]));
|
|
55
|
+
for (const t of teams.values()) {
|
|
56
|
+
if (roles.has(t.id)) errors.push(`${at}: team ${t.id} has the same id as a role`);
|
|
57
|
+
for (const m of t.members) if (!roles.has(m)) errors.push(`${at}: team ${t.id} has unknown role ${m}`);
|
|
58
|
+
}
|
|
59
|
+
const guidelines = new Map((policy.guidelines ?? []).map((g) => [g.id, g]));
|
|
60
|
+
for (const g of guidelines.values()) {
|
|
61
|
+
if (g.path && !existsSync(join(root, g.path))) errors.push(`${at}: guideline ${g.id} not found at ${g.path} (paths are relative to the venture folder)`);
|
|
62
|
+
if (!g.path && !g.url) errors.push(`${at}: guideline ${g.id} needs a path or a url`);
|
|
63
|
+
if (g.url && !g.checked) warnings.push(`${at}: guideline ${g.id} has a url but no checked date`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const person = (id) => roles.get(id)?.occupant === "person";
|
|
67
|
+
for (const c of policy.channels) {
|
|
68
|
+
for (const g of c.guidelines ?? []) if (!guidelines.has(g)) errors.push(`${at}: channel ${c.id} follows unknown guideline ${g}`);
|
|
69
|
+
if (!(c.guidelines ?? []).some((g) => ["brand", "editorial"].includes(guidelines.get(g)?.kind))) warnings.push(`${at}: channel ${c.id} follows no brand or editorial guideline`);
|
|
70
|
+
const onPlatform = ["social", "newsletter", "app-store"].includes(c.kind);
|
|
71
|
+
if (onPlatform && !c.platform) errors.push(`${at}: channel ${c.id} is ${c.kind}, so it names its platform`);
|
|
72
|
+
if (c.platform && !(c.guidelines ?? []).some((g) => guidelines.get(g)?.kind === "platform")) errors.push(`${at}: channel ${c.id} runs on ${c.platform} but cites none of its rules (a guideline of kind platform)`);
|
|
73
|
+
if (["social", "newsletter", "blog"].includes(c.kind) && !c.replies) errors.push(`${at}: channel ${c.id} says how replies and comments are handled (replies: gated, delegated or none)`);
|
|
74
|
+
if (c.replies?.mode === "delegated") {
|
|
75
|
+
const ds = c.replies.delegates ?? [];
|
|
76
|
+
if (!ds.length) errors.push(`${at}: channel ${c.id} delegates replies to no one`);
|
|
77
|
+
for (const id of ds) if (!roles.has(id) && !teams.has(id)) errors.push(`${at}: channel ${c.id} delegates replies to unknown role or team ${id}`);
|
|
78
|
+
if (ds.length && !ds.some((id) => person(id) || teams.get(id)?.members.some(person))) errors.push(`${at}: channel ${c.id} delegates replies to agents only; a person answers for the venture`);
|
|
79
|
+
}
|
|
80
|
+
if (c.config && !existsSync(join(root, c.config))) errors.push(`${at}: channel ${c.id} config not found at ${c.config}`);
|
|
81
|
+
for (const r of c.rules) {
|
|
82
|
+
const rule = `${at}: ${c.id} "${r.content}"`;
|
|
83
|
+
for (const id of [...(r.drafters ?? []), ...r.approvers]) if (!roles.has(id) && !teams.has(id)) errors.push(`${rule}: unknown role or team ${id}`);
|
|
84
|
+
for (const id of r.approvers) {
|
|
85
|
+
if (roles.has(id) && !person(id)) errors.push(`${rule}: ${id} is an agent role; agents draft and check, a person approves`);
|
|
86
|
+
if (teams.has(id) && !teams.get(id).members.some(person)) errors.push(`${rule}: team ${id} has no person, so it cannot approve`);
|
|
87
|
+
}
|
|
88
|
+
if (!r.approvers.some((id) => person(id) || teams.get(id)?.members.some(person))) errors.push(`${rule}: no person approves`);
|
|
89
|
+
for (const l of r.from_layers ?? []) if (v.layers && v.layers[l] === false) warnings.push(`${rule}: publishes from ${l}, which this venture has turned off`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const w of warnings) console.warn(`warning: ${w}`);
|
|
95
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
96
|
+
console.log(`${checked} ventures with a publication policy: every publication passes the gate.`);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Checks that a handoff is ready to execute before anyone starts on it (EE-019): its
|
|
2
|
+
// definition of ready. An agent that claims a handoff runs this first; a gap it finds is a
|
|
3
|
+
// question for the handoff's author, asked before work starts, not an ambiguity discovered
|
|
4
|
+
// halfway through. Every item is objective; judging whether the brief says enough is the
|
|
5
|
+
// holder's first act, recorded with --record.
|
|
6
|
+
//
|
|
7
|
+
// node schema/check-ready.mjs <venture dir> <handoff id>
|
|
8
|
+
// node schema/check-ready.mjs <venture dir> <handoff id> --record --by <role or session>
|
|
9
|
+
//
|
|
10
|
+
// --record writes `ready_check` into the handoff (and moves a draft to ready) only when
|
|
11
|
+
// every item passes. check-execution.mjs refuses an in-progress handoff without one.
|
|
12
|
+
|
|
13
|
+
import { execSync } from "node:child_process";
|
|
14
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
const [dir, id] = process.argv.slice(2);
|
|
18
|
+
if (!dir || !id) { console.error("usage: node schema/check-ready.mjs <venture dir> <handoff id> [--record --by <who>]"); process.exit(2); }
|
|
19
|
+
const opt = (k) => process.argv.includes(k) ? process.argv[process.argv.indexOf(k) + 1] : undefined;
|
|
20
|
+
const root = new URL("..", import.meta.url).pathname;
|
|
21
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
22
|
+
const hPath = join(dir, "operations/handoffs", `${id}.json`);
|
|
23
|
+
const h = load(hPath);
|
|
24
|
+
const items = [];
|
|
25
|
+
const item = (name, ok, why = "") => items.push({ name, ok, why });
|
|
26
|
+
|
|
27
|
+
// 1. The brief says what done looks like and what to do, with no placeholders left.
|
|
28
|
+
const bPath = join(dir, "operations/handoffs", h.brief);
|
|
29
|
+
const brief = existsSync(bPath) ? readFileSync(bPath, "utf8") : "";
|
|
30
|
+
item("brief exists", !!brief, bPath);
|
|
31
|
+
const section = (name) => { const m = brief.match(new RegExp(`^##\\s+(?:\\d+\\.\\s*)?${name}\\b[^\\n]*\\n([\\s\\S]*?)(?=^##\\s|$(?![\\s\\S]))`, "mi")); return m ? m[1].trim() : null; };
|
|
32
|
+
for (const s of ["Outcome", "Work"]) { const t = section(s); item(`brief has its ${s} section, with text`, !!t, t === null ? "missing" : "empty"); }
|
|
33
|
+
const holes = brief.match(/\b(TBD|TODO|FIXME)\b|\?\?\?|<(?:title|role|entity|outcome|id|date)[^>]*>/gi) ?? [];
|
|
34
|
+
item("brief has no placeholders left", !holes.length, holes.slice(0, 3).join(", "));
|
|
35
|
+
|
|
36
|
+
// 2. Everything it names exists.
|
|
37
|
+
const products = new Set(["products", "product"].flatMap((folder) => existsSync(join(dir, folder)) ? readdirSync(join(dir, folder)).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)) : []));
|
|
38
|
+
const missingProducts = (h.products ?? []).filter((p) => !products.has(p));
|
|
39
|
+
item("every product it serves exists", !missingProducts.length, missingProducts.join(", "));
|
|
40
|
+
const logs = [join(root, "docs/decisions/decisions.json"), join(dir, "knowledge/decisions.json")].filter(existsSync).flatMap((f) => load(f).decisions);
|
|
41
|
+
const decisions = new Map(logs.map((d) => [d.id, d]));
|
|
42
|
+
const badDecisions = (h.governed_by ?? []).filter((d) => !decisions.has(d) || ["withdrawn", "superseded"].includes(decisions.get(d).status));
|
|
43
|
+
item("every governing decision exists and is in force or proposed", !badDecisions.length, badDecisions.join(", "));
|
|
44
|
+
// A method assignment (such as a MAD A-NNN) belongs to the build method a venture uses, which is
|
|
45
|
+
// not part of Mentura (EE-038); a handoff may cite one, and this does not check it.
|
|
46
|
+
const missingInputs = (h.inputs ?? []).filter((p) => !existsSync(join(root, p)));
|
|
47
|
+
item("every input it needs exists", !missingInputs.length, missingInputs.join(", "));
|
|
48
|
+
|
|
49
|
+
// 3. The holder can act inside its rights.
|
|
50
|
+
const roles = new Set(load(join(root, "governance/venture-template/roles/agent-roles.json")).roles.map((r) => r.id));
|
|
51
|
+
const classes = new Map(load(join(root, "governance/venture-template/decision-rights.json")).classes.map((c) => [c.id, c]));
|
|
52
|
+
const own = join(dir, "governance/decision-rights.json");
|
|
53
|
+
if (existsSync(own)) for (const c of load(own).classes) classes.set(c.id, { ...classes.get(c.id), ...c });
|
|
54
|
+
item(`role ${h.role} exists`, roles.has(h.role));
|
|
55
|
+
const foreign = h.decision_classes.filter((c) => classes.get(c)?.owner !== h.role);
|
|
56
|
+
item("every decision class it carries belongs to its role", !foreign.length, foreign.join(", "));
|
|
57
|
+
const open = (h.escalations ?? []).filter((e) => !e.answer);
|
|
58
|
+
item("no escalation is waiting for an answer", !open.length, open.map((e) => `${e.class} to ${e.to}`).join(", "));
|
|
59
|
+
item("attempts remain", h.attempts < h.max_attempts, `${h.attempts} of ${h.max_attempts}`);
|
|
60
|
+
|
|
61
|
+
// 4. Done can be proved: the criteria exist and the scripts they call are there.
|
|
62
|
+
const kinds = new Set(h.done_criteria.map((d) => d.kind));
|
|
63
|
+
item("has a conformance and a self-proof criterion", kinds.has("conformance") && kinds.has("self-proof"));
|
|
64
|
+
const scripts = h.done_criteria.filter((d) => d.kind !== "review").flatMap((d) => {
|
|
65
|
+
let cwd = root;
|
|
66
|
+
return d.check.split(/&&|\|/).flatMap((part) => {
|
|
67
|
+
const words = part.trim().split(/\s+/);
|
|
68
|
+
if (words[0] === "cd") { cwd = join(cwd, words[1]); return []; }
|
|
69
|
+
return words.filter((w) => /\.(mjs|js|py|sh)$/.test(w)).map((w) => ({ d: d.id, path: join(cwd, w) }));
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
const lost = scripts.filter((s) => !existsSync(s.path));
|
|
73
|
+
item("every script a criterion runs exists", !lost.length, lost.map((s) => `${s.d}: ${s.path.slice(root.length)}`).join(", "));
|
|
74
|
+
const badReview = h.done_criteria.filter((d) => d.kind === "review" && (!roles.has(d.reviewer) || d.reviewer === h.role));
|
|
75
|
+
item("every review names a reviewer other than the holder", !badReview.length, badReview.map((d) => d.id).join(", "));
|
|
76
|
+
|
|
77
|
+
for (const i of items) console.log(`${i.ok ? "pass" : "FAIL"} ${i.name}${!i.ok && i.why ? `: ${i.why}` : ""}`);
|
|
78
|
+
const ready = items.every((i) => i.ok);
|
|
79
|
+
console.log(ready ? `${h.id} is ready to execute.` : `${h.id} is not ready: ask its author before starting.`);
|
|
80
|
+
if (process.argv.includes("--record")) {
|
|
81
|
+
if (!ready) process.exit(1);
|
|
82
|
+
if (!opt("--by")) { console.error("--record needs --by <role or session>"); process.exit(2); }
|
|
83
|
+
const version = execSync("git rev-parse --short HEAD", { cwd: root, encoding: "utf8" }).trim();
|
|
84
|
+
h.ready_check = { at: new Date().toISOString().replace(/\.\d+Z$/, "Z"), by: opt("--by"), version, items: items.length };
|
|
85
|
+
if (h.status === "draft") h.status = "ready";
|
|
86
|
+
writeFileSync(hPath, JSON.stringify(h, null, 2) + "\n");
|
|
87
|
+
console.log(`recorded in ${hPath}`);
|
|
88
|
+
}
|
|
89
|
+
process.exit(ready ? 0 : 1);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Checks each venture's source map (<venture>/knowledge/sources.json, EE-037) for what its schema
|
|
2
|
+
// cannot state: source ids are unique; each names a connector in the registry
|
|
3
|
+
// (knowledge/tooling/integrations.json) and a write mode that connector supports; a GitHub source
|
|
4
|
+
// names its repository; every record type it maps is a venture record type and goes to a source
|
|
5
|
+
// it lists. The venture, its provenance log and the map itself stay in the venture folder, so they
|
|
6
|
+
// cannot be mapped away. It does not connect to any source: the connector evals do that.
|
|
7
|
+
//
|
|
8
|
+
// node schema/check-sources.mjs <workspace or venture dir>
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { LOCAL, MAP, registry } from "../knowledge/connectors/index.mjs";
|
|
13
|
+
import { ANY, CONTEXT, specificity } from "../knowledge/connectors/resolve.mjs";
|
|
14
|
+
|
|
15
|
+
const dir = process.argv[2];
|
|
16
|
+
if (!dir) { console.error("usage: node schema/check-sources.mjs <workspace or venture dir>"); process.exit(2); }
|
|
17
|
+
const root = new URL("..", import.meta.url).pathname;
|
|
18
|
+
const walk = (d) => readdirSync(d, { withFileTypes: true }).flatMap((e) => e.name === "node_modules" || e.name.startsWith(".") ? []
|
|
19
|
+
: e.isDirectory() ? walk(join(d, e.name)) : e.name === "venture.json" ? [d] : []);
|
|
20
|
+
const model = JSON.parse(readFileSync(join(root, "schema/data-model.json"), "utf8"));
|
|
21
|
+
const ventureTypes = new Set(model.records.filter((r) => r.level === "venture").map((r) => r.id));
|
|
22
|
+
const PINNED = new Set(["venture", "provenance", "knowledge-sources"]);
|
|
23
|
+
const reg = registry();
|
|
24
|
+
// The systems a function's truth can live in (EE-083); a connected one must have code that reads it.
|
|
25
|
+
const catalog = JSON.parse(readFileSync(join(root, "schema/systems-catalog.json"), "utf8"));
|
|
26
|
+
const errors = [];
|
|
27
|
+
let maps = 0;
|
|
28
|
+
|
|
29
|
+
for (const v of walk(dir)) {
|
|
30
|
+
const f = join(v, MAP);
|
|
31
|
+
if (!existsSync(f)) continue;
|
|
32
|
+
maps++;
|
|
33
|
+
const id = JSON.parse(readFileSync(join(v, "venture.json"), "utf8")).id;
|
|
34
|
+
const m = JSON.parse(readFileSync(f, "utf8"));
|
|
35
|
+
const ids = new Set([LOCAL]);
|
|
36
|
+
for (const s of m.sources ?? []) {
|
|
37
|
+
const where = `${id}: source ${s.id}`;
|
|
38
|
+
if (ids.has(s.id)) errors.push(`${where}: duplicate id${s.id === LOCAL ? " (venture is the venture's own folder)" : ""}`);
|
|
39
|
+
ids.add(s.id);
|
|
40
|
+
const c = reg.get(s.connector);
|
|
41
|
+
if (!c) { errors.push(`${where}: no connector ${s.connector} (the registry has ${[...reg.keys()].join(", ")})`); continue; }
|
|
42
|
+
if (s.writes && !c.writes.includes(s.writes)) errors.push(`${where}: ${s.connector} writes ${c.writes.join(" or ")}, not ${s.writes}`);
|
|
43
|
+
if (s.connector === "github" && !s.repo) errors.push(`${where}: a github source names its repo`);
|
|
44
|
+
for (const k of Object.keys(s).filter((k) => !["id", "connector", "writes", "note"].includes(k))) if (!(c.options ?? []).includes(k)) errors.push(`${where}: ${s.connector} takes no option ${k}`);
|
|
45
|
+
}
|
|
46
|
+
for (const [type, src] of Object.entries(m.records ?? {})) {
|
|
47
|
+
if (!ventureTypes.has(type)) errors.push(`${id}: ${type} is not a venture record type`);
|
|
48
|
+
if (PINNED.has(type)) errors.push(`${id}: ${type} stays in the venture folder`);
|
|
49
|
+
if (!ids.has(src)) errors.push(`${id}: ${type} goes to ${src}, which is not one of its sources`);
|
|
50
|
+
}
|
|
51
|
+
// The matrix (EE-042): every rule names a known record type and a known source, and two rules
|
|
52
|
+
// that can hold at once never tie. Product and account ids are not checked here: those records
|
|
53
|
+
// may themselves live in another source.
|
|
54
|
+
const rules = m.rules ?? [];
|
|
55
|
+
rules.forEach((rule, i) => {
|
|
56
|
+
const where = `${id}: rule ${i + 1} (${rule.record}${rule.attribute !== ANY ? `.${rule.attribute}` : ""})`;
|
|
57
|
+
if (!ventureTypes.has(rule.record)) errors.push(`${where}: ${rule.record} is not a venture record type`);
|
|
58
|
+
if (PINNED.has(rule.record)) errors.push(`${where}: ${rule.record} stays in the venture folder`);
|
|
59
|
+
if (!ids.has(rule.system_of_record)) errors.push(`${where}: system of record ${rule.system_of_record} is not one of its sources`);
|
|
60
|
+
for (const s of rule.survivorship?.also_in ?? []) if (!ids.has(s) || s === rule.system_of_record) errors.push(`${where}: survivorship names ${s}, which is not another of its sources`);
|
|
61
|
+
});
|
|
62
|
+
for (const [fn, f] of Object.entries(m.functions ?? {})) for (const s of f.systems) {
|
|
63
|
+
const sys = catalog.systems[s.system];
|
|
64
|
+
if (!sys) { errors.push(`${id}: ${fn} keeps its truth in ${s.system}, which is not in schema/systems-catalog.json`); continue; }
|
|
65
|
+
if (s.status === "connected" && !sys.connect) errors.push(`${id}: ${fn} says ${s.system} is connected, but no code reads ${sys.label} yet; it is pointed`);
|
|
66
|
+
if (s.source && !ids.has(s.source)) errors.push(`${id}: ${fn} names source ${s.source}, which is not in sources`);
|
|
67
|
+
}
|
|
68
|
+
const overlap = (a, b) => a.record === b.record && ["attribute", ...CONTEXT].every((k) => a[k] === ANY || b[k] === ANY || a[k] === b[k]);
|
|
69
|
+
for (let i = 0; i < rules.length; i++) for (let j = i + 1; j < rules.length; j++)
|
|
70
|
+
if (overlap(rules[i], rules[j]) && specificity(rules[i]) === specificity(rules[j]) && rules[i].attribute === rules[j].attribute)
|
|
71
|
+
errors.push(`${id}: rules ${i + 1} and ${j + 1} (${rules[i].record}) can both hold and tie at the same specificity; narrow one`);
|
|
72
|
+
}
|
|
73
|
+
if (errors.length) { console.error(errors.join("\n")); process.exit(1); }
|
|
74
|
+
console.log(`${maps} source maps: every source has a connector, every record type a source, every function's systems are known, and no two matrix rules tie.`);
|