mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
Read the repo-root build path, and stop overstating what a flip forbids
Two findings from Greptile on #579, both about the same key seen from different roots. `appendBuildPathDirective` searched projectRoot and cwd but never repoRoot, while `checkBuildPathUnset` reads both. In a monorepo that committed the preference once at the root, the two disagreed in the worst direction: the staleness finding stayed silent because a value existed, and the directive never named it, so nothing on screen explained why the recorded default was not being honored. Roots are now ordered nearest first, workspace over repo root, with regression tests for both the fallback and the override. The ANSWER line for a flipped path said "never write it to settings". The page indeed never writes it, but the sentence read as a rule and applied itself to new-work's one-time offer, which exists for exactly the case a flip creates: a project with no recorded default, asked once after the round closes. It now states what the page does and names the exception. The same report's first issue also named context.mjs, and that part does not hold: its directive is emitted only when a value is already recorded, which is precisely when session-only is the correct instruction. Left as is. Written with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
65de2d294b
commit
c0e7f2d778
@@ -1299,8 +1299,15 @@ function readBuildPathAt(root) {
|
||||
return value ? { value, source } : null;
|
||||
}
|
||||
|
||||
// Roots in precedence order, nearest first: the active workspace decides, and
|
||||
// the repo root is the fallback a monorepo commits once for every app in it.
|
||||
// `checkBuildPathUnset` already reads both, so leaving repoRoot out here made
|
||||
// the two disagree: the finding stayed silent because a value existed while the
|
||||
// directive never named it, which is the one combination nobody can debug.
|
||||
function appendBuildPathDirective(parts, ctx) {
|
||||
const roots = [...new Set([ctx?.projectRoot, process.cwd()].filter(Boolean).map((root) => path.resolve(root)))];
|
||||
const roots = [...new Set(
|
||||
[ctx?.projectRoot, process.cwd(), ctx?.repoRoot].filter(Boolean).map((root) => path.resolve(root)),
|
||||
)];
|
||||
for (const root of roots) {
|
||||
const found = readBuildPathAt(root);
|
||||
if (!found) continue;
|
||||
|
||||
@@ -161,8 +161,12 @@ function printAnswer(raw) {
|
||||
console.log('FOLLOWUP OPEN: the table stays open and the page is showing a loading hand. Deliver the next round now with --update --key <key> --payload <file>, then collect it with --wait; never leave the page waiting on a round you have not sent.');
|
||||
}
|
||||
if (a.buildPath === 'comp' || a.buildPath === 'code') {
|
||||
// The page never writes the flip itself, but "never write it" overstated
|
||||
// that into a rule the agent then applied to new-work's one-time offer,
|
||||
// which exists for exactly this case: a flip on a project that had no
|
||||
// recorded default is the only moment the preference is ever asked for.
|
||||
const origin = a.buildPathFlipped
|
||||
? 'flipped on the page, so it binds this session only; never write it to settings'
|
||||
? 'flipped on the page, so it binds this session only, and the page never writes it back; the sole exception is new-work’s one-time offer, on a project that had no recorded default at all, which asks after the round closes and writes the answer to .impeccable/config.json'
|
||||
: 'the round’s recorded default';
|
||||
console.log(`BUILD PATH: ${a.buildPath} (${origin}). ${a.buildPath === 'comp'
|
||||
? 'Comp-led: the chosen card’s comp is law; generate it before building when it does not exist yet, and the finish review audits the build against it.'
|
||||
|
||||
@@ -1094,6 +1094,36 @@ describe('context.mjs CLI', () => {
|
||||
write('.impeccable/config.json', JSON.stringify({ buildPath: 'code-first' }));
|
||||
assert.equal(run().stdout.includes('BUILD_PATH_DEFAULT'), false);
|
||||
});
|
||||
|
||||
// A monorepo commits the preference once at the repo root for every app in
|
||||
// it. Reading only projectRoot left the staleness finding (which does read
|
||||
// both) silent while the directive never named the value.
|
||||
describe('in a monorepo', () => {
|
||||
const writeWorkspace = () => {
|
||||
write('package.json', JSON.stringify({ private: true, workspaces: ['apps/*'] }));
|
||||
write('turbo.json', JSON.stringify({ tasks: {} }));
|
||||
write('PRODUCT.md', '# Root product\n');
|
||||
write('apps/dashboard/src/App.jsx', 'export default function App() { return "d"; }\n');
|
||||
};
|
||||
const runFromWorkspace = () => spawnSync(process.execPath, [SCRIPT_PATH, '--target', 'apps/dashboard/src/App.jsx'], {
|
||||
cwd: scratch,
|
||||
encoding: 'utf8',
|
||||
env: { ...process.env, IMPECCABLE_NO_UPDATE_CHECK: '1', IMPECCABLE_NO_STALENESS_CHECK: '1' },
|
||||
});
|
||||
|
||||
it('falls back to the repo-root value for a workspace that sets none', () => {
|
||||
writeWorkspace();
|
||||
write('.impeccable/config.json', JSON.stringify({ buildPath: 'code' }));
|
||||
assert.match(runFromWorkspace().stdout, /BUILD_PATH_DEFAULT: code/);
|
||||
});
|
||||
|
||||
it('lets the workspace override the repo root, nearest root first', () => {
|
||||
writeWorkspace();
|
||||
write('.impeccable/config.json', JSON.stringify({ buildPath: 'code' }));
|
||||
write('apps/dashboard/.impeccable/config.json', JSON.stringify({ buildPath: 'comp' }));
|
||||
assert.match(runFromWorkspace().stdout, /BUILD_PATH_DEFAULT: comp/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps the manual-detector directive out of early context when the current provider hook is active', () => {
|
||||
|
||||
Reference in New Issue
Block a user